@oh-my-pi/pi-catalog 18.1.15 → 18.1.17
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 +17 -0
- package/README.md +20 -0
- package/dist/types/compat/auth-ids.d.ts +2 -2
- package/dist/types/fireworks-model-id.d.ts +4 -4
- package/dist/types/models.d.ts +10 -6
- package/dist/types/pricing.d.ts +5 -0
- package/dist/types/provider-models/descriptor-types.d.ts +15 -0
- package/dist/types/provider-models/descriptors.d.ts +13 -1
- package/dist/types/provider-models/openai-compat.d.ts +28 -2
- package/dist/types/types.d.ts +19 -1
- package/dist/types/wire/github-copilot.d.ts +19 -0
- package/package.json +4 -4
- package/src/build.ts +8 -0
- package/src/compat/auth-ids.ts +2 -0
- package/src/compat/axes.ts +2 -0
- package/src/compat/resolve.ts +16 -4
- package/src/compat/rules/README.md +37 -0
- package/src/compat/rules/auth/_order.kdl +1 -1
- package/src/compat/rules/auth/commandcode.kdl +13 -0
- package/src/compat/rules/auth/firepass.kdl +4 -5
- package/src/compat/rules/providers/commandcode.kdl +601 -0
- package/src/compat/rules/providers/deepseek.kdl +71 -1
- package/src/compat/rules/providers/firepass.kdl +7 -3
- package/src/compat/rules/runtime/behavior.kdl +5 -0
- package/src/compat/rules.json +1785 -13
- package/src/fireworks-model-id.ts +4 -4
- package/src/model-manager.ts +6 -1
- package/src/models.json +6075 -84
- package/src/models.ts +93 -19
- package/src/pricing.ts +136 -0
- package/src/provider-models/descriptor-types.ts +15 -0
- package/src/provider-models/descriptors.ts +16 -1
- package/src/provider-models/openai-compat.ts +125 -3
- package/src/types.ts +22 -1
- package/src/wire/github-copilot.ts +26 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.1.17] - 2026-09-10
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added DeepSeek cost estimates that follow published peak/off-peak rates.
|
|
10
|
+
- Added dated, announced price changes to the catalog, so rates switch on their effective date (e.g. DeepSeek Pro moving to Flash rates).
|
|
11
|
+
- Added Command Code as a built-in provider with API-key login, live model discovery, per-model pricing, native OpenAI/Anthropic-compatible routing, cache-aware token usage, and TTFT metrics ([#11391](https://github.com/can1357/oh-my-pi/pull/11391) by [@CherkaSSH](https://github.com/CherkaSSH)).
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Fixed Command Code models outside the verified effort registry offering unsupported reasoning effort controls, and bundled the live Command Code catalog so fresh installs resolve the default model without waiting for discovery ([#11595](https://github.com/can1357/oh-my-pi/pull/11595) by [@H4vC](https://github.com/H4vC)).
|
|
16
|
+
- Fixed the bundled `deepseek-flash` row shipping without context limits: it now carries its documented 1M context / 384K output so offline context accounting enforces the real window.
|
|
17
|
+
|
|
18
|
+
## [18.1.16] - 2026-09-09
|
|
19
|
+
|
|
20
|
+
- Updated Fire Pass (`firepass`) login validation probe to `accounts/fireworks/routers/glm-5p2-fast` and bundled `glm-5.2-fast` and `kimi-k3-fast` models in place of decommissioned `kimi-k2.6-turbo` ([#10859](https://github.com/can1357/oh-my-pi/pull/10859) by [@olegpulatov](https://github.com/olegpulatov)).
|
|
21
|
+
|
|
5
22
|
## [18.1.14] - 2026-09-07
|
|
6
23
|
|
|
7
24
|
### Fixed
|
package/README.md
CHANGED
|
@@ -38,6 +38,26 @@ bun add @oh-my-pi/pi-catalog
|
|
|
38
38
|
|
|
39
39
|
Ships TypeScript source directly (no build step); requires Bun ≥ 1.3.14.
|
|
40
40
|
|
|
41
|
+
## Cost calculation
|
|
42
|
+
|
|
43
|
+
The `models` subpath (also exported from the root) provides timestamp-aware pricing helpers:
|
|
44
|
+
|
|
45
|
+
| API | Result |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| `calculateCost(model, usage, timestamp?)` | Updates and returns `usage.cost` using `model.cost`. |
|
|
48
|
+
| `calculateUsageCost(cost, usage, timestamp?)` | Updates and returns `usage.cost` using a `ModelCost`. |
|
|
49
|
+
| `calculateUncachedInputCost(cost, promptInputTokens, timestamp?)` | Returns the cost of a fully uncached prompt. |
|
|
50
|
+
| `getTimeBasedPricingPeriod(cost, timestamp?)` | Returns `"peak"`, `"off-peak"`, or `undefined` without a schedule. |
|
|
51
|
+
| `getNextTimeBasedPricingTransition(cost, timestamp?)` | Returns the next actual peak/off-peak change strictly after the timestamp, or `undefined` if none exists. |
|
|
52
|
+
|
|
53
|
+
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
|
+
|
|
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.
|
|
56
|
+
|
|
57
|
+
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
|
+
|
|
59
|
+
Schedules are materialized from the [`time-based-cost` KDL axis](src/compat/rules/README.md#time-based-pricing); this does not add a `timeBased` input field to the coding agent's `models.yml`. See [user-facing pricing behavior](../../docs/models.md#usage-costs-and-time-based-pricing) for DeepSeek rates, dates, and footer indicators.
|
|
60
|
+
|
|
41
61
|
## References
|
|
42
62
|
|
|
43
63
|
- [Monorepo README](https://github.com/can1357/oh-my-pi#readme)
|
|
@@ -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" | "azure" | "baseten" | "bedrock-mantle" | "cerebras" | "cline-pass" | "cloudflare-ai-gateway" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "exa" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google" | "google-antigravity" | "google-gemini-cli" | "google-vertex" | "groq" | "huggingface" | "kagi" | "kilo" | "kimi-code" | "litellm" | "llama.cpp" | "lm-studio" | "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" | "synthetic" | "tavily" | "together" | "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";
|
|
2
|
+
export type AuthProviderId = "abliteration" | "aiand" | "aimlapi" | "alibaba-coding-plan" | "alibaba-token-plan" | "amazon-bedrock" | "anthropic" | "azure" | "baseten" | "bedrock-mantle" | "cerebras" | "cline-pass" | "cloudflare-ai-gateway" | "commandcode" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "exa" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google" | "google-antigravity" | "google-gemini-cli" | "google-vertex" | "groq" | "huggingface" | "kagi" | "kilo" | "kimi-code" | "litellm" | "llama.cpp" | "lm-studio" | "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" | "synthetic" | "tavily" | "together" | "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";
|
|
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" | "cline-pass" | "cloudflare-ai-gateway" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "exa" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google-antigravity" | "google-gemini-cli" | "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" | "synthetic" | "tavily" | "together" | "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" | "cline-pass" | "cloudflare-ai-gateway" | "commandcode" | "coreweave" | "cursor" | "deepinfra" | "deepseek" | "devin" | "exa" | "firepass" | "fireworks" | "github-copilot" | "gitlab-duo" | "gitlab-duo-agent" | "gmi-cloud" | "google-antigravity" | "google-gemini-cli" | "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" | "synthetic" | "tavily" | "together" | "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,10 +1,10 @@
|
|
|
1
1
|
export declare function toFireworksPublicModelId(modelId: string): string;
|
|
2
2
|
export declare function toFireworksWireModelId(modelId: string): string;
|
|
3
3
|
/**
|
|
4
|
-
* Fire Pass exposes
|
|
5
|
-
*
|
|
6
|
-
* We keep a friendly public id (e.g. `
|
|
7
|
-
* to the wire form (`accounts/fireworks/routers/
|
|
4
|
+
* Fire Pass exposes subscription models through dedicated router endpoints
|
|
5
|
+
* at `accounts/fireworks/routers/<id>` rather than the `models/` namespace.
|
|
6
|
+
* We keep a friendly public id (e.g. `glm-5.2-fast`, `kimi-k3-fast`) in the catalog
|
|
7
|
+
* and translate to the wire form (`accounts/fireworks/routers/glm-5p2-fast`) at request time.
|
|
8
8
|
*/
|
|
9
9
|
export declare function toFirepassPublicModelId(modelId: string): string;
|
|
10
10
|
export declare function toFirepassWireModelId(modelId: string): string;
|
package/dist/types/models.d.ts
CHANGED
|
@@ -4,12 +4,16 @@ export type GeneratedProvider = keyof typeof MODELS;
|
|
|
4
4
|
export declare function getBundledModel<TApi extends Api = Api>(provider: GeneratedProvider, modelId: string): Model<TApi>;
|
|
5
5
|
export declare function getBundledProviders(): KnownProvider[];
|
|
6
6
|
export declare function getBundledModels(provider: GeneratedProvider): Model<Api>[];
|
|
7
|
-
/**
|
|
8
|
-
export declare function
|
|
9
|
-
/**
|
|
10
|
-
export declare function
|
|
11
|
-
/** Price
|
|
12
|
-
export declare function
|
|
7
|
+
/** Return the recurring UTC tariff period, independently of its monetary multiplier. */
|
|
8
|
+
export declare function getTimeBasedPricingPeriod(cost: ModelCost, timestamp?: number): "peak" | "off-peak" | undefined;
|
|
9
|
+
/** Return the next actual peak/off-peak change strictly after the Unix-ms timestamp. */
|
|
10
|
+
export declare function getNextTimeBasedPricingTransition(cost: ModelCost, timestamp?: number): number | undefined;
|
|
11
|
+
/** Price a fully uncached prompt at its request timestamp (Unix ms); scheduled prices default to now. */
|
|
12
|
+
export declare function calculateUncachedInputCost(cost: ModelCost, promptInputTokens: number, timestamp?: number): number;
|
|
13
|
+
/** Price usage at its request timestamp (Unix ms); only scheduled prices default to now. */
|
|
14
|
+
export declare function calculateUsageCost(cost: ModelCost, usage: Usage, timestamp?: number): Usage["cost"];
|
|
15
|
+
/** Price usage at its request timestamp (Unix ms); preserve the resulting monetary amounts for display. */
|
|
16
|
+
export declare function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage, timestamp?: number): Usage["cost"];
|
|
13
17
|
/**
|
|
14
18
|
* Check if two models are equal by comparing both their id and provider.
|
|
15
19
|
* Returns false if either model is null or undefined.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { TimeBasedCost } from "./types.js";
|
|
2
|
+
/** Validate serialized schedules before admitting cached model rows. */
|
|
3
|
+
export declare function isTimeBasedCost(value: unknown): value is TimeBasedCost;
|
|
4
|
+
/** KDL object children are named records; normalize them once while constructing the model. */
|
|
5
|
+
export declare function materializeTimeBasedCost(value: unknown): TimeBasedCost;
|
|
@@ -34,6 +34,14 @@ export interface ProviderDescriptor {
|
|
|
34
34
|
dynamicModelsAuthoritative?: boolean;
|
|
35
35
|
/** Catalog discovery configuration. Only providers with this field participate in generate-models.ts. */
|
|
36
36
|
catalogDiscovery?: CatalogDiscoveryConfig;
|
|
37
|
+
/**
|
|
38
|
+
* When true, generator backfills never copy reasoning/input/limits from
|
|
39
|
+
* same-id rows on other providers into this provider's rows. Set for
|
|
40
|
+
* providers whose endpoint discovery is the deployment truth and whose
|
|
41
|
+
* corrections live in KDL, so a stencil.so or canonical-family reference
|
|
42
|
+
* cannot reintroduce foreign metadata.
|
|
43
|
+
*/
|
|
44
|
+
skipCrossProviderReferenceFills?: boolean;
|
|
37
45
|
}
|
|
38
46
|
/** A provider descriptor that has catalog discovery configured. */
|
|
39
47
|
export type CatalogProviderDescriptor = ProviderDescriptor & {
|
|
@@ -68,6 +76,13 @@ export interface ProviderCatalogEntry {
|
|
|
68
76
|
readonly dynamicModelsAuthoritative?: boolean;
|
|
69
77
|
/** Catalog discovery configuration for generate-models.ts. */
|
|
70
78
|
readonly catalogDiscovery?: CatalogDiscoveryConfig;
|
|
79
|
+
/**
|
|
80
|
+
* When true, generator backfills never copy reasoning/input/limits from
|
|
81
|
+
* same-id rows on other providers into this provider's rows. Set for
|
|
82
|
+
* providers whose endpoint discovery is the deployment truth and whose
|
|
83
|
+
* corrections live in KDL.
|
|
84
|
+
*/
|
|
85
|
+
readonly skipCrossProviderReferenceFills?: boolean;
|
|
71
86
|
/**
|
|
72
87
|
* Built bespoke by the coding-agent runtime (OAuth-token-driven managers);
|
|
73
88
|
* excluded from `PROVIDER_DESCRIPTORS` even though models are discoverable.
|
|
@@ -96,6 +96,18 @@ export declare const CATALOG_PROVIDERS: readonly [{
|
|
|
96
96
|
readonly catalogDiscovery: {
|
|
97
97
|
readonly label: "Cloudflare AI Gateway";
|
|
98
98
|
};
|
|
99
|
+
}, {
|
|
100
|
+
readonly id: "commandcode";
|
|
101
|
+
readonly defaultModel: "claude-sonnet-4-6";
|
|
102
|
+
readonly envVars: readonly ["COMMAND_CODE_API_KEY", "COMMANDCODE_API_KEY"];
|
|
103
|
+
readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<import("../index.js").Api, unknown>;
|
|
104
|
+
readonly allowUnauthenticated: true;
|
|
105
|
+
readonly dynamicModelsAuthoritative: true;
|
|
106
|
+
readonly catalogDiscovery: {
|
|
107
|
+
readonly label: "Command Code";
|
|
108
|
+
readonly allowUnauthenticated: true;
|
|
109
|
+
};
|
|
110
|
+
readonly skipCrossProviderReferenceFills: true;
|
|
99
111
|
}, {
|
|
100
112
|
readonly id: "cursor";
|
|
101
113
|
readonly defaultModel: "claude-4.6-opus-high";
|
|
@@ -147,7 +159,7 @@ export declare const CATALOG_PROVIDERS: readonly [{
|
|
|
147
159
|
};
|
|
148
160
|
}, {
|
|
149
161
|
readonly id: "firepass";
|
|
150
|
-
readonly defaultModel: "
|
|
162
|
+
readonly defaultModel: "glm-5.2-fast";
|
|
151
163
|
readonly envVars: readonly ["FIREPASS_API_KEY"];
|
|
152
164
|
readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<"openai-completions", unknown>;
|
|
153
165
|
}, {
|
|
@@ -332,14 +332,15 @@ export interface FireworksModelManagerConfig {
|
|
|
332
332
|
fetch?: FetchImpl;
|
|
333
333
|
}
|
|
334
334
|
export declare function fireworksModelManagerOptions(config?: FireworksModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
|
335
|
+
export declare const FIREPASS_STATIC_MODELS: readonly ModelSpec<"openai-completions">[];
|
|
335
336
|
export interface FirepassModelManagerConfig {
|
|
336
337
|
apiKey?: string;
|
|
337
338
|
baseUrl?: string;
|
|
338
339
|
fetch?: FetchImpl;
|
|
339
340
|
}
|
|
340
341
|
/**
|
|
341
|
-
* Fire Pass is a Fireworks subscription product that exposes
|
|
342
|
-
*
|
|
342
|
+
* Fire Pass is a Fireworks subscription product that exposes router models
|
|
343
|
+
* (GLM 5.2 Fast, Kimi K3 Fast) under `accounts/fireworks/routers/<id>`.
|
|
343
344
|
* The dedicated `fpk_…` keys do not authorize `/v1/models`, so this manager
|
|
344
345
|
* never performs dynamic discovery — the bundled catalog entry is canonical.
|
|
345
346
|
* See https://docs.fireworks.ai/firepass.
|
|
@@ -719,3 +720,28 @@ export declare const MODELS_DEV_CATALOG_PROVIDER_IDS: readonly string[];
|
|
|
719
720
|
* stricter startup budget and for deterministic timeout tests.
|
|
720
721
|
*/
|
|
721
722
|
export declare function modelsDevCatalogFallback(providerId: string, fetchImpl?: FetchImpl, timeoutMs?: number): ModelsDevFallback<Api> | undefined;
|
|
723
|
+
/**
|
|
724
|
+
* Configuration for the Command Code Provider API model manager.
|
|
725
|
+
*
|
|
726
|
+
* `baseUrl` overrides the Provider API base path for testing; it is
|
|
727
|
+
* normalized to the shared `/provider` root (a trailing `/v1` is stripped)
|
|
728
|
+
* so Claude ids route to the Anthropic-compatible Messages endpoint at the
|
|
729
|
+
* root while every other id uses chat completions under `/v1`.
|
|
730
|
+
*/
|
|
731
|
+
export interface CommandCodeModelManagerConfig {
|
|
732
|
+
apiKey?: string;
|
|
733
|
+
baseUrl?: string;
|
|
734
|
+
fetch?: FetchImpl;
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Builds the Command Code model manager: a mixed-protocol OpenAI-compatible
|
|
738
|
+
* discovery client. The public `/v1/models` catalog is fetched once per
|
|
739
|
+
* options instance; `mapModel` pins each row's transport from the
|
|
740
|
+
* `api-routes` table (Claude ids to `anthropic-messages`, everything else to
|
|
741
|
+
* `openai-completions`) and seeds neutral capability defaults. Reviewed
|
|
742
|
+
* Command Code policy (effort ladders, pricing, limits, modalities) is
|
|
743
|
+
* applied later by `buildModel` from `providers/commandcode.kdl` — the
|
|
744
|
+
* mapper never inherits another provider's reasoning, rates, image support,
|
|
745
|
+
* or context window.
|
|
746
|
+
*/
|
|
747
|
+
export declare function commandCodeModelManagerOptions(config?: CommandCodeModelManagerConfig): ModelManagerOptions<Api>;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -863,9 +863,27 @@ export interface LongContextTokenCost extends TokenCost {
|
|
|
863
863
|
/** Whether the long-context tier starts exactly at `inputThreshold`. */
|
|
864
864
|
inputThresholdInclusive?: boolean;
|
|
865
865
|
}
|
|
866
|
-
/**
|
|
866
|
+
/** Recurring UTC peak interval; weekdays use Sunday = 0, and the end is exclusive. */
|
|
867
|
+
export interface PeakPricingWindow {
|
|
868
|
+
weekdays: readonly number[];
|
|
869
|
+
startMinute: number;
|
|
870
|
+
endMinute: number;
|
|
871
|
+
}
|
|
872
|
+
/** Complete replacement rate card effective from a Unix-millisecond timestamp. */
|
|
873
|
+
export interface EffectiveTokenCost extends TokenCost {
|
|
874
|
+
effectiveFrom: number;
|
|
875
|
+
longContext?: LongContextTokenCost;
|
|
876
|
+
}
|
|
877
|
+
/** Scheduled discounts applied after selecting the effective rate card and context tier. */
|
|
878
|
+
export interface TimeBasedCost {
|
|
879
|
+
offPeakMultiplier: number;
|
|
880
|
+
peakWindows: readonly PeakPricingWindow[];
|
|
881
|
+
effectiveRates?: readonly EffectiveTokenCost[];
|
|
882
|
+
}
|
|
883
|
+
/** Base token rates plus optional long-context and time-based pricing. */
|
|
867
884
|
export interface ModelCost extends TokenCost {
|
|
868
885
|
longContext?: LongContextTokenCost;
|
|
886
|
+
timeBased?: TimeBasedCost;
|
|
869
887
|
}
|
|
870
888
|
/**
|
|
871
889
|
* Exact local content tokenizer family for a model.
|
|
@@ -11,6 +11,16 @@ export declare const COPILOT_CAPI_IDENTITY_HEADERS: {
|
|
|
11
11
|
readonly "Copilot-Harness-Id": "copilot-sdk";
|
|
12
12
|
readonly "Openai-Intent": "conversation-agent";
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* Chat-surface identity for Copilot chat and model-policy requests.
|
|
16
|
+
* Some Business organizations gate premium models per client surface and
|
|
17
|
+
* block the CLI identity while allowing chat (issue #11372), so chat traffic
|
|
18
|
+
* defaults to this id with `COPILOT_INTEGRATION_ID` as an explicit pin and a
|
|
19
|
+
* one-shot CLI retry on denial. Model discovery keeps the CLI identity above:
|
|
20
|
+
* it unlocks enterprise/experimental models and listing is not policy-gated
|
|
21
|
+
* the way chat completions are.
|
|
22
|
+
*/
|
|
23
|
+
export declare const COPILOT_CHAT_INTEGRATION_ID: "copilot-chat";
|
|
14
24
|
/**
|
|
15
25
|
* Copilot API version sent on `api.githubcopilot.com` requests (`/models`,
|
|
16
26
|
* chat endpoints). Newer versions unlock tiered context metadata: `/models`
|
|
@@ -42,6 +52,15 @@ export declare const COPILOT_DISCOVERY_HEADERS: {
|
|
|
42
52
|
};
|
|
43
53
|
/** Preserve model-specific headers while enforcing the current Copilot API identity. */
|
|
44
54
|
export declare function mergeCopilotApiHeaders(headers?: Readonly<Record<string, string>>): Record<string, string>;
|
|
55
|
+
/**
|
|
56
|
+
* Validate an explicit `Copilot-Integration-Id` override.
|
|
57
|
+
* omp identifies as the Copilot CLI (`copilot-developer-cli`); some Business
|
|
58
|
+
* organizations allow Chat clients but block CLI/agentic ones, rejecting every
|
|
59
|
+
* model with HTTP 403 on an otherwise valid token (issue #11372). Callers pass
|
|
60
|
+
* the raw `COPILOT_INTEGRATION_ID` value; blank or CR/LF-bearing values are
|
|
61
|
+
* rejected so the header stays well-formed and the default identity applies.
|
|
62
|
+
*/
|
|
63
|
+
export declare function normalizeCopilotIntegrationId(value: unknown): string | undefined;
|
|
45
64
|
export type ParsedGitHubCopilotApiKey = {
|
|
46
65
|
accessToken: string;
|
|
47
66
|
enterpriseUrl?: string;
|
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.1.
|
|
4
|
+
"version": "18.1.17",
|
|
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.1.
|
|
39
|
-
"@oh-my-pi/pi-utils": "18.1.
|
|
38
|
+
"@oh-my-pi/omptype": "18.1.17",
|
|
39
|
+
"@oh-my-pi/pi-utils": "18.1.17"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@bgotink/kdl": "0.4.0",
|
|
43
|
-
"@oh-my-pi/pi-ai": "18.1.
|
|
43
|
+
"@oh-my-pi/pi-ai": "18.1.17",
|
|
44
44
|
"@types/bun": "^1.3.14"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
package/src/build.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { resolveModelPolicy } from "./compat/resolve";
|
|
11
11
|
import type { ModelIdentity } from "./compat/types";
|
|
12
12
|
import { resolveModelTokenizer } from "./model-tokenizer";
|
|
13
|
+
import { materializeTimeBasedCost } from "./pricing";
|
|
13
14
|
import type { Api, Model, ModelSpec } from "./types";
|
|
14
15
|
import { cleanModelName } from "./utils";
|
|
15
16
|
|
|
@@ -126,6 +127,9 @@ export function applyCatalogCorrections(
|
|
|
126
127
|
const cacheWrite = numberField(patch, "cacheWrite");
|
|
127
128
|
if (cacheWrite !== undefined) model.cost.cacheWrite = cacheWrite;
|
|
128
129
|
}
|
|
130
|
+
if (catalog.timeBased !== undefined) {
|
|
131
|
+
model.cost = { ...model.cost, timeBased: materializeTimeBasedCost(catalog.timeBased) };
|
|
132
|
+
}
|
|
129
133
|
const limitsPatch = objectPayload(catalog.limitsPatch);
|
|
130
134
|
if (limitsPatch !== undefined) {
|
|
131
135
|
const contextWindow = numberField(limitsPatch, "contextWindow");
|
|
@@ -208,6 +212,10 @@ export function buildModel<TApi extends Api>(spec: ModelSpec<TApi>): Model<TApi>
|
|
|
208
212
|
const supportsComputerUseConfig = explicitComputerUseConfig(spec);
|
|
209
213
|
const model: Model<TApi> = {
|
|
210
214
|
...spec,
|
|
215
|
+
// An exact `thinking-efforts` rule upgrades a stale `reasoning: false`
|
|
216
|
+
// discovery default (see `resolveThinkingPolicy`); materialize the
|
|
217
|
+
// correction so transports and the picker see a reasoning-capable model.
|
|
218
|
+
reasoning: spec.reasoning || policy.thinking !== undefined,
|
|
211
219
|
name: cleanModelName(spec.name),
|
|
212
220
|
identity: policy.identity,
|
|
213
221
|
requiresGlyphTokenization: policy.identity.class === "anthropic",
|
package/src/compat/auth-ids.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type AuthProviderId =
|
|
|
15
15
|
| "cerebras"
|
|
16
16
|
| "cline-pass"
|
|
17
17
|
| "cloudflare-ai-gateway"
|
|
18
|
+
| "commandcode"
|
|
18
19
|
| "coreweave"
|
|
19
20
|
| "cursor"
|
|
20
21
|
| "deepinfra"
|
|
@@ -95,6 +96,7 @@ export type LoginProviderId =
|
|
|
95
96
|
| "cerebras"
|
|
96
97
|
| "cline-pass"
|
|
97
98
|
| "cloudflare-ai-gateway"
|
|
99
|
+
| "commandcode"
|
|
98
100
|
| "coreweave"
|
|
99
101
|
| "cursor"
|
|
100
102
|
| "deepinfra"
|
package/src/compat/axes.ts
CHANGED
|
@@ -259,6 +259,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
|
|
|
259
259
|
"thinking-prefix-binding": { key: "prefixBinding", set: "thinking", shape: "scalar" },
|
|
260
260
|
"thinking-suppress-when-off": { key: "suppressWhenOff", set: "thinking", shape: "scalar" },
|
|
261
261
|
"thinking-supports-display": { key: "supportsDisplay", set: "thinking", shape: "scalar" },
|
|
262
|
+
"thinking-upgrade-neutral": { key: "upgradeNeutral", set: "thinking", shape: "scalar" },
|
|
262
263
|
|
|
263
264
|
// ── catalog metadata ──
|
|
264
265
|
"apply-patch-tool-type": {
|
|
@@ -286,6 +287,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
|
|
|
286
287
|
},
|
|
287
288
|
priority: { key: "priority", set: "catalog", shape: "scalar" },
|
|
288
289
|
"service-tier-cost": { key: "serviceTierCost", set: "catalog", shape: "object" },
|
|
290
|
+
"time-based-cost": { key: "timeBased", set: "catalog", shape: "object" },
|
|
289
291
|
};
|
|
290
292
|
|
|
291
293
|
/** Records applicable to each API family; used by `resolve.ts` when applying wire axes. */
|
package/src/compat/resolve.ts
CHANGED
|
@@ -1021,6 +1021,7 @@ interface RuleThinking {
|
|
|
1021
1021
|
suppressWhenOff?: boolean;
|
|
1022
1022
|
supportsDisplay?: boolean;
|
|
1023
1023
|
prefixBinding?: boolean;
|
|
1024
|
+
upgradeNeutral?: boolean;
|
|
1024
1025
|
}
|
|
1025
1026
|
|
|
1026
1027
|
function readRuleThinking(axes: ResolvedAxes): RuleThinking {
|
|
@@ -1040,6 +1041,7 @@ function readRuleThinking(axes: ResolvedAxes): RuleThinking {
|
|
|
1040
1041
|
if (typeof raw.suppressWhenOff === "boolean") out.suppressWhenOff = raw.suppressWhenOff;
|
|
1041
1042
|
if (typeof raw.supportsDisplay === "boolean") out.supportsDisplay = raw.supportsDisplay;
|
|
1042
1043
|
if (typeof raw.prefixBinding === "boolean") out.prefixBinding = raw.prefixBinding;
|
|
1044
|
+
if (typeof raw.upgradeNeutral === "boolean") out.upgradeNeutral = raw.upgradeNeutral;
|
|
1043
1045
|
return out;
|
|
1044
1046
|
}
|
|
1045
1047
|
|
|
@@ -1065,7 +1067,18 @@ function resolveThinkingPolicy<TApi extends Api>(
|
|
|
1065
1067
|
axes: ResolvedAxes,
|
|
1066
1068
|
compat: CompatOf<TApi>,
|
|
1067
1069
|
): ThinkingConfig | undefined {
|
|
1068
|
-
|
|
1070
|
+
const rule = readRuleThinking(axes);
|
|
1071
|
+
const explicitThinking =
|
|
1072
|
+
spec.thinking !== undefined && Array.isArray(spec.thinking.efforts) && spec.thinking.efforts.length > 0
|
|
1073
|
+
? spec.thinking
|
|
1074
|
+
: undefined;
|
|
1075
|
+
// An explicit wire vocabulary is authoritative when discovery reports no
|
|
1076
|
+
// reasoning (e.g. Synthetic's `none`-only off-switch): reviewed KDL must
|
|
1077
|
+
// not re-expand it into an unadvertised ladder. Absent metadata is
|
|
1078
|
+
// repaired only where KDL opts in with `thinking-upgrade-neutral`
|
|
1079
|
+
// alongside an exact `thinking-efforts` ladder (the cascade upgrade for
|
|
1080
|
+
// stale source capability data); otherwise the neutral default holds.
|
|
1081
|
+
if (!spec.reasoning && (explicitThinking !== undefined || rule.upgradeNeutral !== true)) return undefined;
|
|
1069
1082
|
if (
|
|
1070
1083
|
spec.provider === "cline-pass" &&
|
|
1071
1084
|
compat !== undefined &&
|
|
@@ -1075,9 +1088,8 @@ function resolveThinkingPolicy<TApi extends Api>(
|
|
|
1075
1088
|
return undefined;
|
|
1076
1089
|
}
|
|
1077
1090
|
if (omitsWireReasoningEffort(spec.api, compat)) return undefined;
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
return fillExplicitThinking(spec, facts, compat, spec.thinking, rule);
|
|
1091
|
+
if (explicitThinking !== undefined) {
|
|
1092
|
+
return fillExplicitThinking(spec, facts, compat, explicitThinking, rule);
|
|
1081
1093
|
}
|
|
1082
1094
|
if (compat !== undefined && "trustExplicitThinkingOnly" in compat && compat.trustExplicitThinkingOnly === true) {
|
|
1083
1095
|
return undefined;
|
|
@@ -207,6 +207,43 @@ The three value shapes are:
|
|
|
207
207
|
A rule cannot assign the same resolved axis twice in one block.
|
|
208
208
|
One object axis carries a computed form: `long-context-cost` accepts either the absolute rates (`input-threshold` + `input`/`output`/`cache-read`/`cache-write`) or `input-threshold` + `multiplier` (with optional `input-threshold-inclusive`), which derives the tier from the row's live base price at build time so the rule tracks upstream list-price updates (xAI's SuperGrok 200K tier). Rows without a token price carry no tier.
|
|
209
209
|
|
|
210
|
+
### Time-based pricing
|
|
211
|
+
|
|
212
|
+
The catalog object axis `time-based-cost` materializes into `ModelCost.timeBased`. It uses **named child objects**, not KDL arrays or repeated anonymous windows. For example, inside a matching provider/model scope:
|
|
213
|
+
|
|
214
|
+
```kdl
|
|
215
|
+
time-based-cost {
|
|
216
|
+
off-peak-multiplier 0.5
|
|
217
|
+
peak-windows {
|
|
218
|
+
morning {
|
|
219
|
+
weekdays "1,2,3,4,5"
|
|
220
|
+
start-minute 60
|
|
221
|
+
end-minute 240
|
|
222
|
+
}
|
|
223
|
+
afternoon {
|
|
224
|
+
weekdays "1,2,3,4,5"
|
|
225
|
+
start-minute 360
|
|
226
|
+
end-minute 600
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
effective-rates {
|
|
230
|
+
flash-pricing {
|
|
231
|
+
effective-from "2026-09-14T04:00:00Z"
|
|
232
|
+
input 0.30
|
|
233
|
+
output 1.20
|
|
234
|
+
cache-read 0.006
|
|
235
|
+
cache-write 0
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
`morning`, `afternoon`, and `flash-pricing` are arbitrary unique object names, discarded when the payload is normalized into arrays. `weekdays` is a comma-separated string of distinct UTC weekday numbers (`0` = Sunday through `6` = Saturday), without spaces. Each window has integer minutes with `0 <= start-minute < end-minute <= 1440`; its start is inclusive and end exclusive. Split overnight windows across days. Outside the union of peak windows, the nonnegative `off-peak-multiplier` applies to token costs.
|
|
242
|
+
|
|
243
|
+
`effective-rates` is optional. Each entry requires a distinct valid ISO UTC `effective-from` (`YYYY-MM-DDTHH:mm:ssZ` or with three fractional-second digits) and all four nonnegative per-million-token rates. The latest entry at or before the request timestamp replaces the entire base card; before the first entry, the base card applies. An entry may contain a `long-context` object with `input-threshold`, optional `input-threshold-inclusive`, and all four absolute rates. Effective rates do not inherit the base card's long-context tier. Selection order is effective card, context tier, then tariff multiplier.
|
|
244
|
+
|
|
245
|
+
The recurring schedule and dated DeepSeek transition above come from [DeepSeek's official pricing](https://api-docs.deepseek.com/quick_start/pricing); see `providers/deepseek.kdl` for the complete rules and [the catalog API](../../../README.md#cost-calculation) for timestamp semantics. This is catalog policy metadata, not a supported schedule syntax for the coding agent's `models.yml`.
|
|
246
|
+
|
|
210
247
|
### Precedence and ambiguity
|
|
211
248
|
|
|
212
249
|
Rules resolve independently per axis. A matching rule is ranked by:
|
|
@@ -5,7 +5,7 @@ login-order "openai-codex" "anthropic" "zai" "zai-coding-plan" "kimi-code" "open
|
|
|
5
5
|
"cursor" "devin" "google-antigravity" "google-gemini-cli" "openai-codex-device" "xai" "xai-oauth" \
|
|
6
6
|
"gitlab-duo" "gitlab-duo-agent" "alibaba-coding-plan" "alibaba-token-plan" "aiand" "abliteration" "zhipu-coding-plan" \
|
|
7
7
|
"umans" "qwen-portal" "sakana" "minimax-code" "minimax-code-cn" "xiaomi" "xiaomi-token-plan-sgp" \
|
|
8
|
-
"xiaomi-token-plan-ams" "xiaomi-token-plan-cn" "firepass" "cline-pass" "deepseek" "muse-code" "meta" "moonshot" \
|
|
8
|
+
"xiaomi-token-plan-ams" "xiaomi-token-plan-cn" "firepass" "cline-pass" "commandcode" "deepseek" "muse-code" "meta" "moonshot" \
|
|
9
9
|
"cerebras" "baseten" "fireworks" "together" "nvidia" "novita" "deepinfra" "huggingface" "perplexity" \
|
|
10
10
|
"qianfan" "venice" "siliconflow" "siliconflow-cn" "synthetic" "nanogpt" "wafer-serverless" "coreweave" \
|
|
11
11
|
"vercel-ai-gateway" "cloudflare-ai-gateway" "litellm" "kilo" "zenmux" "opencode-zen" "opencode-go" \
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// No `validate` probe on purpose: GET /provider/v1/models is public (200
|
|
2
|
+
// with no or bogus credentials, verified 2026-09-09), so a models-endpoint
|
|
3
|
+
// probe could never reject a bad key. A chat-completions probe would bill
|
|
4
|
+
// the key and 403 for Go-plan keys that are still valid CLI credentials.
|
|
5
|
+
auth "commandcode" {
|
|
6
|
+
name "Command Code"
|
|
7
|
+
env "COMMAND_CODE_API_KEY" "COMMANDCODE_API_KEY"
|
|
8
|
+
login "api-key" {
|
|
9
|
+
auth-url "https://commandcode.ai/studio"
|
|
10
|
+
instructions "Create or copy a Provider API key from Command Code Studio"
|
|
11
|
+
prompt "Paste your Command Code API key" placeholder="user_..."
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
auth "firepass" {
|
|
2
|
-
name "Fire Pass (Fireworks
|
|
2
|
+
name "Fire Pass (Fireworks subscription)"
|
|
3
3
|
login "api-key" {
|
|
4
4
|
// Fire Pass is a Fireworks subscription product whose dedicated `fpk_…` API
|
|
5
|
-
// keys are scoped to
|
|
6
|
-
//
|
|
7
|
-
// pings the chat completions endpoint with the router id directly.
|
|
5
|
+
// keys are scoped to router endpoints. The key does NOT authorize `/v1/models`,
|
|
6
|
+
// so validation pings the chat completions endpoint with the router id directly.
|
|
8
7
|
// See https://docs.fireworks.ai/firepass.
|
|
9
8
|
auth-url "https://app.fireworks.ai/settings/users/api-keys"
|
|
10
9
|
instructions "Create a dedicated Fire Pass API key in the Fireworks dashboard"
|
|
11
10
|
prompt "Paste your Fire Pass API key" placeholder="fpk_..."
|
|
12
|
-
validate "chat-completions" label="Fire Pass" base-url="https://api.fireworks.ai/inference/v1" model="accounts/fireworks/routers/
|
|
11
|
+
validate "chat-completions" label="Fire Pass" base-url="https://api.fireworks.ai/inference/v1" model="accounts/fireworks/routers/glm-5p2-fast"
|
|
13
12
|
}
|
|
14
13
|
}
|