@linxiraos/pi-catalog 1.1.13 → 1.1.15
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 +2 -69
- package/README.md +20 -0
- package/dist/types/compat/auth-ids.d.ts +2 -2
- 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 +20 -0
- package/dist/types/provider-models/openai-compat.d.ts +44 -0
- package/dist/types/types.d.ts +43 -2
- package/dist/types/wire/charm-hyper.d.ts +21 -0
- package/dist/types/wire/github-copilot.d.ts +19 -0
- package/package.json +4 -4
- package/src/build.ts +16 -2
- package/src/compat/auth-ids.ts +4 -0
- package/src/compat/axes.ts +9 -0
- package/src/compat/resolve.ts +18 -4
- package/src/compat/rules/README.md +37 -0
- package/src/compat/rules/auth/_order.kdl +1 -1
- package/src/compat/rules/auth/charm-hyper.kdl +19 -0
- package/src/compat/rules/auth/commandcode.kdl +13 -0
- package/src/compat/rules/classes/anthropic.kdl +41 -0
- package/src/compat/rules/classes/deepseek.kdl +11 -0
- package/src/compat/rules/classes/minimax.kdl +4 -2
- package/src/compat/rules/providers/amazon-bedrock.kdl +7 -0
- package/src/compat/rules/providers/anthropic.kdl +8 -0
- package/src/compat/rules/providers/charm-hyper.kdl +82 -0
- package/src/compat/rules/providers/commandcode.kdl +601 -0
- package/src/compat/rules/providers/deepseek.kdl +83 -1
- package/src/compat/rules/providers/opencode-go.kdl +22 -0
- package/src/compat/rules/providers/opencode-zen.kdl +12 -0
- package/src/compat/rules/runtime/behavior.kdl +5 -0
- package/src/compat/rules.json +2143 -131
- package/src/model-manager.ts +27 -13
- package/src/models.json +12953 -5481
- package/src/models.ts +93 -19
- package/src/pricing.ts +136 -0
- package/src/provider-models/cache-provider-id.ts +28 -4
- package/src/provider-models/descriptor-types.ts +15 -0
- package/src/provider-models/descriptors.ts +36 -0
- package/src/provider-models/openai-compat.ts +297 -3
- package/src/types.ts +46 -1
- package/src/wire/charm-hyper.ts +26 -0
- package/src/wire/github-copilot.ts +26 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,74 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
-
## [1.1.
|
|
5
|
+
## [1.1.15] - 2026-09-16
|
|
6
6
|
|
|
7
|
-
- 上游 v18.1.
|
|
7
|
+
- 上游 v18.1.17–v18.1.21 同步:DeepSeek V4.1 Flash 原生多模态保留图片输入;GitHub Copilot OAuth 公共 GitHub/GHE 双 client-id;renovate 系模型目录配置面。
|
|
8
8
|
|
|
9
|
-
## [1.1.11] - 2026-09-08
|
|
10
|
-
|
|
11
|
-
### Added
|
|
12
|
-
|
|
13
|
-
- Added Muse Code as a provider with Muse Spark models and live account-scoped discovery; subscriptions resolve a compact edit-prompt variant, cutting recurring per-request tool bytes without touching other providers. Added Meta's `max` reasoning effort tier to Muse Spark 1.3 (standard) on the Meta Model API and Muse Code.
|
|
14
|
-
|
|
15
|
-
### Fixed
|
|
16
|
-
|
|
17
|
-
- GPT-6 Astra keeps its documented 1.05M-token window with `/extended-context` on or off; Codex Astra defaults to 272K, clamps explicit context-window overrides to the server-honored ceiling, uses the documented 922K input cap inside the 1.05M total, and bills long-context requests at the documented 2x input / 1.5x output tier above 272K input (Codex subscription route exempt with free cache writes).
|
|
18
|
-
- Fixed GitHub Copilot enterprise-only model ids inheriting another provider's wire routing (e.g. `gpt-5.6-sol-fast` pinning every request to the `-none` sibling id regardless of thinking level).
|
|
19
|
-
- Extended-context catalog rebuilds resolve each model's maximum window once per process.
|
|
20
|
-
|
|
21
|
-
## [1.1.10] - 2026-09-07
|
|
22
|
-
|
|
23
|
-
### Added
|
|
24
|
-
|
|
25
|
-
- Muse Code provider baseline from the v18.1.12 sync: provider registration, Spark models, live discovery, `max` reasoning tier.
|
|
26
|
-
|
|
27
|
-
### Fixed
|
|
28
|
-
|
|
29
|
-
- Fixed OpenCode Go/Zen live model discovery missing `x-opencode-session` attribution: discovery requests carry the stable install id so requests flagged as `Bun fetch` get the required session header.
|
|
30
|
-
- Fixed GPT-6 Astra requests through GitHub Copilot failing with an unsupported endpoint error.
|
|
31
|
-
|
|
32
|
-
## [1.1.9] - 2026-09-05
|
|
33
|
-
|
|
34
|
-
- v18.1.10 sync baseline; retired pi-hashline catalog entry removed from the version-line catalogs.
|
|
35
|
-
|
|
36
|
-
## [1.1.6] - 2026-08-30
|
|
37
|
-
|
|
38
|
-
- 同步上游 OMP v18.0.9(`cc14e04f075d`)。
|
|
39
|
-
|
|
40
|
-
## [1.1.5] - 2026-08-26
|
|
41
|
-
|
|
42
|
-
- 同步上游 OMP v18.0.5 / v18.0.6:新增 DeepInfra / Yolo-Auto 提供商标识。
|
|
43
|
-
|
|
44
|
-
## [1.1.2] - 2026-08-25
|
|
45
|
-
|
|
46
|
-
### Fixed
|
|
47
|
-
|
|
48
|
-
- Republished as 1.1.2 to reset the `latest` tag after the broken 1.1.0 (no functional change over 1.1.1).
|
|
49
|
-
|
|
50
|
-
## [1.1.1] - 2026-08-25
|
|
51
|
-
|
|
52
|
-
### Fixed
|
|
53
|
-
|
|
54
|
-
- Published tarballs now carry real dependency versions instead of Bun's `catalog:` protocol (1.1.0 installs failed with "Unsupported URL Type catalog:").
|
|
55
|
-
|
|
56
|
-
## [1.1.0] - 2026-08-25
|
|
57
|
-
|
|
58
|
-
### Changed
|
|
59
|
-
|
|
60
|
-
- 同步上游 OMP v18.0.3 / v18.0.4(内部运行时与构建改进,无独立用户可见变更)。
|
|
61
|
-
|
|
62
|
-
## [1.0.1] - 2026-08-14
|
|
63
|
-
|
|
64
|
-
- Reset the version to 1.0.0 and republished under the `@linxiraos/*` scope, breaking from the `@linxiraos` version lineage.
|
|
65
|
-
|
|
66
|
-
## [1.0.0] - 2026-08-13
|
|
67
|
-
|
|
68
|
-
### Changed
|
|
69
|
-
|
|
70
|
-
- Reset the version to 1.0.0 and republished under the `@linxiraos/*` scope, breaking from the `@linxiraos` version lineage.
|
|
71
|
-
- Bundled model metadata is prebuilt during generation, reducing catalog startup work.
|
|
72
|
-
|
|
73
|
-
### Fixed
|
|
74
|
-
|
|
75
|
-
- Fixed tool-call turn failures for `opencode-go/muse-spark-1.2` and related variants by ensuring API transport pins apply to live discovery and automatically inferring response routes for gateway-first OpenCode models ([#8957](https://github.com/can1357/oh-my-pi/issues/8957)).
|
package/README.md
CHANGED
|
@@ -38,6 +38,26 @@ bun add @linxiraos/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/Linxira-OS/linxira-zeta#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" | "charm-hyper" | "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" | "charm-hyper" | "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";
|
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.
|
|
@@ -88,6 +88,14 @@ export declare const CATALOG_PROVIDERS: readonly [{
|
|
|
88
88
|
readonly catalogDiscovery: {
|
|
89
89
|
readonly label: "Cerebras";
|
|
90
90
|
};
|
|
91
|
+
}, {
|
|
92
|
+
readonly id: "charm-hyper";
|
|
93
|
+
readonly defaultModel: "glm-5.3";
|
|
94
|
+
readonly envVars: readonly ["CHARM_HYPER_API_KEY", "HYPER_API_KEY"];
|
|
95
|
+
readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<"openai-completions", unknown>;
|
|
96
|
+
readonly allowUnauthenticated: true;
|
|
97
|
+
readonly dynamicModelsAuthoritative: true;
|
|
98
|
+
readonly skipCrossProviderReferenceFills: true;
|
|
91
99
|
}, {
|
|
92
100
|
readonly id: "cloudflare-ai-gateway";
|
|
93
101
|
readonly defaultModel: "anthropic/claude-opus-4-8";
|
|
@@ -96,6 +104,18 @@ export declare const CATALOG_PROVIDERS: readonly [{
|
|
|
96
104
|
readonly catalogDiscovery: {
|
|
97
105
|
readonly label: "Cloudflare AI Gateway";
|
|
98
106
|
};
|
|
107
|
+
}, {
|
|
108
|
+
readonly id: "commandcode";
|
|
109
|
+
readonly defaultModel: "claude-sonnet-4-6";
|
|
110
|
+
readonly envVars: readonly ["COMMAND_CODE_API_KEY", "COMMANDCODE_API_KEY"];
|
|
111
|
+
readonly createModelManagerOptions: (config: ModelManagerConfig) => import("../index.js").ModelManagerOptions<import("../index.js").Api, unknown>;
|
|
112
|
+
readonly allowUnauthenticated: true;
|
|
113
|
+
readonly dynamicModelsAuthoritative: true;
|
|
114
|
+
readonly catalogDiscovery: {
|
|
115
|
+
readonly label: "Command Code";
|
|
116
|
+
readonly allowUnauthenticated: true;
|
|
117
|
+
};
|
|
118
|
+
readonly skipCrossProviderReferenceFills: true;
|
|
99
119
|
}, {
|
|
100
120
|
readonly id: "cursor";
|
|
101
121
|
readonly defaultModel: "claude-4.6-opus-high";
|
|
@@ -720,3 +720,47 @@ export declare const MODELS_DEV_CATALOG_PROVIDER_IDS: readonly string[];
|
|
|
720
720
|
* stricter startup budget and for deterministic timeout tests.
|
|
721
721
|
*/
|
|
722
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>;
|
|
748
|
+
/**
|
|
749
|
+
* Configuration for the Charm Hyper model manager.
|
|
750
|
+
*
|
|
751
|
+
* `baseUrl` overrides the gateway root for tests and self-hosted proxies; a
|
|
752
|
+
* value that omits the `/v1` surface gains one, so a host-only override
|
|
753
|
+
* behaves like every sibling provider's.
|
|
754
|
+
*/
|
|
755
|
+
export interface CharmHyperModelManagerConfig {
|
|
756
|
+
apiKey?: string;
|
|
757
|
+
baseUrl?: string;
|
|
758
|
+
fetch?: FetchImpl;
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Charm Hyper's gateway catalog. `/v1/models` is public and carries the live
|
|
762
|
+
* tariff, so discovery runs with or without a key and the snapshot is
|
|
763
|
+
* authoritative: a model the gateway stops serving is pruned rather than kept
|
|
764
|
+
* alive by a stale bundled row.
|
|
765
|
+
*/
|
|
766
|
+
export declare function charmHyperModelManagerOptions(config?: CharmHyperModelManagerConfig): ModelManagerOptions<"openai-completions">;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -409,6 +409,20 @@ export interface OpenAICompat {
|
|
|
409
409
|
export interface AnthropicCompat {
|
|
410
410
|
/** Whether thinking requests may include `context_management` and its beta header. Default: true. */
|
|
411
411
|
supportsContextManagement?: boolean;
|
|
412
|
+
/**
|
|
413
|
+
* Whether the model lineage supports Anthropic server-side compaction
|
|
414
|
+
* (`compact-2026-01-12`: the `compact_20260112` edit and replayed
|
|
415
|
+
* `compaction` blocks). Rule-owned per model line; the beta covers the
|
|
416
|
+
* adaptive-thinking generation onward and rejects older lines. Default: false.
|
|
417
|
+
*/
|
|
418
|
+
supportsServerCompaction?: boolean;
|
|
419
|
+
/**
|
|
420
|
+
* Whether the model is served by the first-party Anthropic provider (its
|
|
421
|
+
* default route is the official API). Rule-owned on the provider; the
|
|
422
|
+
* compaction transport pairs it with a per-request effective-URL check
|
|
423
|
+
* because reroutes leave it stale-true. Default: false.
|
|
424
|
+
*/
|
|
425
|
+
firstPartyProvider?: boolean;
|
|
412
426
|
/**
|
|
413
427
|
* Whether requests may carry `output_config.effort` (and its effort beta
|
|
414
428
|
* header). Vertex AI rejects the field/header. Default: true.
|
|
@@ -756,6 +770,13 @@ export type ResolvedAnthropicCompat = Required<Omit<AnthropicCompat, "streamIdle
|
|
|
756
770
|
* env headers, and cache-TTL shaping without per-request URL parsing.
|
|
757
771
|
*/
|
|
758
772
|
officialEndpoint: boolean;
|
|
773
|
+
/**
|
|
774
|
+
* The model is served by the first-party Anthropic provider. Unlike
|
|
775
|
+
* `officialEndpoint` (URL-derived per deployment), this is provider
|
|
776
|
+
* identity for compaction gating, always paired with a per-request
|
|
777
|
+
* effective-URL check.
|
|
778
|
+
*/
|
|
779
|
+
firstPartyProvider: boolean;
|
|
759
780
|
};
|
|
760
781
|
/**
|
|
761
782
|
* Compatibility settings for the devin-agent (Codeium Cascade) API. Cascade
|
|
@@ -863,9 +884,27 @@ export interface LongContextTokenCost extends TokenCost {
|
|
|
863
884
|
/** Whether the long-context tier starts exactly at `inputThreshold`. */
|
|
864
885
|
inputThresholdInclusive?: boolean;
|
|
865
886
|
}
|
|
866
|
-
/**
|
|
887
|
+
/** Recurring UTC peak interval; weekdays use Sunday = 0, and the end is exclusive. */
|
|
888
|
+
export interface PeakPricingWindow {
|
|
889
|
+
weekdays: readonly number[];
|
|
890
|
+
startMinute: number;
|
|
891
|
+
endMinute: number;
|
|
892
|
+
}
|
|
893
|
+
/** Complete replacement rate card effective from a Unix-millisecond timestamp. */
|
|
894
|
+
export interface EffectiveTokenCost extends TokenCost {
|
|
895
|
+
effectiveFrom: number;
|
|
896
|
+
longContext?: LongContextTokenCost;
|
|
897
|
+
}
|
|
898
|
+
/** Scheduled discounts applied after selecting the effective rate card and context tier. */
|
|
899
|
+
export interface TimeBasedCost {
|
|
900
|
+
offPeakMultiplier: number;
|
|
901
|
+
peakWindows: readonly PeakPricingWindow[];
|
|
902
|
+
effectiveRates?: readonly EffectiveTokenCost[];
|
|
903
|
+
}
|
|
904
|
+
/** Base token rates plus optional long-context and time-based pricing. */
|
|
867
905
|
export interface ModelCost extends TokenCost {
|
|
868
906
|
longContext?: LongContextTokenCost;
|
|
907
|
+
timeBased?: TimeBasedCost;
|
|
869
908
|
}
|
|
870
909
|
/**
|
|
871
910
|
* Exact local content tokenizer family for a model.
|
|
@@ -892,6 +931,8 @@ export interface Model<TApi extends Api = Api> {
|
|
|
892
931
|
requiresGlyphTokenization?: boolean;
|
|
893
932
|
/** Whether this model requires Cursor's tool-schema combiner projection. */
|
|
894
933
|
requiresCursorToolSchemaProjection?: boolean;
|
|
934
|
+
/** Whether this model requires tool-result images hoisted into sibling user content blocks. */
|
|
935
|
+
requiresToolResultImageHoisting?: boolean;
|
|
895
936
|
/**
|
|
896
937
|
* Model id to send on the wire when it differs from `id`. Used by catalog
|
|
897
938
|
* variants that present one upstream model under several local entries —
|
|
@@ -1065,7 +1106,7 @@ export interface Model<TApi extends Api = Api> {
|
|
|
1065
1106
|
* vocabulary of `buildModel`. Identical to `Model` except `compat` carries the
|
|
1066
1107
|
* sparse override shape and nothing is resolved yet.
|
|
1067
1108
|
*/
|
|
1068
|
-
export interface ModelSpec<TApi extends Api = Api> extends Omit<Model<TApi>, "compat" | "identity" | "compatConfig" | "requiresGlyphTokenization" | "requiresCursorToolSchemaProjection" | "supportsComputerUseConfig"> {
|
|
1109
|
+
export interface ModelSpec<TApi extends Api = Api> extends Omit<Model<TApi>, "compat" | "identity" | "compatConfig" | "requiresGlyphTokenization" | "requiresCursorToolSchemaProjection" | "requiresToolResultImageHoisting" | "supportsComputerUseConfig"> {
|
|
1069
1110
|
/** Sparse compatibility overrides; resolved into `Model.compat` by `buildModel`. */
|
|
1070
1111
|
compat?: CompatConfigOf<TApi>;
|
|
1071
1112
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Charm Hyper gateway endpoint, shared so a host migration — or a self-hosted
|
|
3
|
+
* proxy override — touches a single module.
|
|
4
|
+
*/
|
|
5
|
+
export declare const CHARM_HYPER_API_BASE_URL = "https://hyper.charm.land/v1";
|
|
6
|
+
/**
|
|
7
|
+
* Resolve a configured Charm Hyper base URL onto the gateway's `/v1` surface.
|
|
8
|
+
*
|
|
9
|
+
* Every consumer must agree on this, because they key different things off the
|
|
10
|
+
* result: inference and discovery target it, `/usage` sends a bearer token to
|
|
11
|
+
* it, and the model cache namespace is hashed from it. Three separate copies
|
|
12
|
+
* previously disagreed for a blank value — the model manager treated it as
|
|
13
|
+
* absent and used the canonical host, while the others produced a bare `/v1` —
|
|
14
|
+
* so a whitespace-only override silently split inference, balance checks and
|
|
15
|
+
* caching across different endpoints.
|
|
16
|
+
*
|
|
17
|
+
* A blank or whitespace-only value therefore means "not configured" and
|
|
18
|
+
* resolves to the canonical host; anything else keeps its host and gains the
|
|
19
|
+
* `/v1` segment if it omits one.
|
|
20
|
+
*/
|
|
21
|
+
export declare function normalizeCharmHyperBaseUrl(baseUrl?: string): string;
|
|
@@ -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": "@linxiraos/pi-catalog",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.15",
|
|
5
5
|
"description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
|
|
6
6
|
"homepage": "https://linxira-os.github.io/zeta/",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"gen:proto": "bun scripts/generate-protocols.ts"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@linxiraos/pi-omptype": "1.1.
|
|
39
|
-
"@linxiraos/pi-utils": "1.1.
|
|
38
|
+
"@linxiraos/pi-omptype": "1.1.15",
|
|
39
|
+
"@linxiraos/pi-utils": "1.1.15"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@bgotink/kdl": "0.4.0",
|
|
43
|
-
"@linxiraos/pi-ai": "1.1.
|
|
43
|
+
"@linxiraos/pi-ai": "1.1.15",
|
|
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
|
|
|
@@ -33,8 +34,8 @@ function isInputModalities(value: unknown): value is ("text" | "image")[] {
|
|
|
33
34
|
* corrections (`cost-patch`, `limits-patch`, `long-context-cost`,
|
|
34
35
|
* `context-window-floor`) overwrite upstream values; selection metadata
|
|
35
36
|
* (`priority`, `apply-patch-tool-type`, `service-tier-cost`,
|
|
36
|
-
* `requires-cursor-tool-schema-projection`)
|
|
37
|
-
* `context-promotion-target` fills only when the spec left it unset.
|
|
37
|
+
* `requires-cursor-tool-schema-projection`, `requires-tool-result-image-hoisting`)
|
|
38
|
+
* is rule-owned; `context-promotion-target` fills only when the spec left it unset.
|
|
38
39
|
*/
|
|
39
40
|
function applyCatalogAssignments<TApi extends Api>(model: Model<TApi>, catalog: Record<string, unknown>): void {
|
|
40
41
|
const serviceTierCost = objectPayload(catalog.serviceTierCost);
|
|
@@ -62,6 +63,12 @@ function applyCatalogAssignments<TApi extends Api>(model: Model<TApi>, catalog:
|
|
|
62
63
|
} else {
|
|
63
64
|
delete model.requiresCursorToolSchemaProjection;
|
|
64
65
|
}
|
|
66
|
+
const requiresToolResultImageHoisting = catalog.requiresToolResultImageHoisting;
|
|
67
|
+
if (requiresToolResultImageHoisting === true) {
|
|
68
|
+
model.requiresToolResultImageHoisting = true;
|
|
69
|
+
} else {
|
|
70
|
+
delete model.requiresToolResultImageHoisting;
|
|
71
|
+
}
|
|
65
72
|
const contextPromotionTarget = catalog.contextPromotionTarget;
|
|
66
73
|
if (typeof contextPromotionTarget === "string" && model.contextPromotionTarget === undefined) {
|
|
67
74
|
model.contextPromotionTarget = contextPromotionTarget;
|
|
@@ -126,6 +133,9 @@ export function applyCatalogCorrections(
|
|
|
126
133
|
const cacheWrite = numberField(patch, "cacheWrite");
|
|
127
134
|
if (cacheWrite !== undefined) model.cost.cacheWrite = cacheWrite;
|
|
128
135
|
}
|
|
136
|
+
if (catalog.timeBased !== undefined) {
|
|
137
|
+
model.cost = { ...model.cost, timeBased: materializeTimeBasedCost(catalog.timeBased) };
|
|
138
|
+
}
|
|
129
139
|
const limitsPatch = objectPayload(catalog.limitsPatch);
|
|
130
140
|
if (limitsPatch !== undefined) {
|
|
131
141
|
const contextWindow = numberField(limitsPatch, "contextWindow");
|
|
@@ -208,6 +218,10 @@ export function buildModel<TApi extends Api>(spec: ModelSpec<TApi>): Model<TApi>
|
|
|
208
218
|
const supportsComputerUseConfig = explicitComputerUseConfig(spec);
|
|
209
219
|
const model: Model<TApi> = {
|
|
210
220
|
...spec,
|
|
221
|
+
// An exact `thinking-efforts` rule upgrades a stale `reasoning: false`
|
|
222
|
+
// discovery default (see `resolveThinkingPolicy`); materialize the
|
|
223
|
+
// correction so transports and the picker see a reasoning-capable model.
|
|
224
|
+
reasoning: spec.reasoning || policy.thinking !== undefined,
|
|
211
225
|
name: cleanModelName(spec.name),
|
|
212
226
|
identity: policy.identity,
|
|
213
227
|
requiresGlyphTokenization: policy.identity.class === "anthropic",
|
package/src/compat/auth-ids.ts
CHANGED
|
@@ -13,8 +13,10 @@ export type AuthProviderId =
|
|
|
13
13
|
| "baseten"
|
|
14
14
|
| "bedrock-mantle"
|
|
15
15
|
| "cerebras"
|
|
16
|
+
| "charm-hyper"
|
|
16
17
|
| "cline-pass"
|
|
17
18
|
| "cloudflare-ai-gateway"
|
|
19
|
+
| "commandcode"
|
|
18
20
|
| "coreweave"
|
|
19
21
|
| "cursor"
|
|
20
22
|
| "deepinfra"
|
|
@@ -93,8 +95,10 @@ export type LoginProviderId =
|
|
|
93
95
|
| "anthropic"
|
|
94
96
|
| "baseten"
|
|
95
97
|
| "cerebras"
|
|
98
|
+
| "charm-hyper"
|
|
96
99
|
| "cline-pass"
|
|
97
100
|
| "cloudflare-ai-gateway"
|
|
101
|
+
| "commandcode"
|
|
98
102
|
| "coreweave"
|
|
99
103
|
| "cursor"
|
|
100
104
|
| "deepinfra"
|
package/src/compat/axes.ts
CHANGED
|
@@ -192,6 +192,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
|
|
|
192
192
|
"disable-adaptive-thinking": wire("disableAdaptiveThinking", ["anthropic"]),
|
|
193
193
|
"disable-strict-tools": wire("disableStrictTools", ["anthropic"]),
|
|
194
194
|
"escape-builtin-tool-names": wire("escapeBuiltinToolNames", ["anthropic"]),
|
|
195
|
+
"first-party-provider": wire("firstPartyProvider", ["anthropic"]),
|
|
195
196
|
"inject-claude-code-instruction": wire("injectClaudeCodeInstruction", ["anthropic"]),
|
|
196
197
|
"official-endpoint": wire("officialEndpoint", ["anthropic", "openai-responses"]),
|
|
197
198
|
"replay-unsigned-thinking": wire("replayUnsignedThinking", ["anthropic"]),
|
|
@@ -205,6 +206,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
|
|
|
205
206
|
"supports-mid-conversation-system": wire("supportsMidConversationSystem", ["anthropic"]),
|
|
206
207
|
"supports-mid-conversation-tool-changes": wire("supportsMidConversationToolChanges", ["anthropic"]),
|
|
207
208
|
"supports-per-message-effort": wire("supportsPerMessageEffort", ["anthropic"]),
|
|
209
|
+
"supports-server-compaction": wire("supportsServerCompaction", ["anthropic"]),
|
|
208
210
|
"supports-thinking-binding-controls": wire("supportsThinkingBindingControls", ["anthropic"]),
|
|
209
211
|
"supports-turn-scoped-system": wire("supportsTurnScopedSystem", ["anthropic"]),
|
|
210
212
|
|
|
@@ -259,6 +261,7 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
|
|
|
259
261
|
"thinking-prefix-binding": { key: "prefixBinding", set: "thinking", shape: "scalar" },
|
|
260
262
|
"thinking-suppress-when-off": { key: "suppressWhenOff", set: "thinking", shape: "scalar" },
|
|
261
263
|
"thinking-supports-display": { key: "supportsDisplay", set: "thinking", shape: "scalar" },
|
|
264
|
+
"thinking-upgrade-neutral": { key: "upgradeNeutral", set: "thinking", shape: "scalar" },
|
|
262
265
|
|
|
263
266
|
// ── catalog metadata ──
|
|
264
267
|
"apply-patch-tool-type": {
|
|
@@ -283,8 +286,14 @@ export const AXES: Readonly<Record<string, AxisDef>> = {
|
|
|
283
286
|
set: "catalog",
|
|
284
287
|
shape: "scalar",
|
|
285
288
|
},
|
|
289
|
+
"requires-tool-result-image-hoisting": {
|
|
290
|
+
key: "requiresToolResultImageHoisting",
|
|
291
|
+
set: "catalog",
|
|
292
|
+
shape: "scalar",
|
|
293
|
+
},
|
|
286
294
|
priority: { key: "priority", set: "catalog", shape: "scalar" },
|
|
287
295
|
"service-tier-cost": { key: "serviceTierCost", set: "catalog", shape: "object" },
|
|
296
|
+
"time-based-cost": { key: "timeBased", set: "catalog", shape: "object" },
|
|
288
297
|
};
|
|
289
298
|
|
|
290
299
|
/** Records applicable to each API family; used by `resolve.ts` when applying wire axes. */
|
package/src/compat/resolve.ts
CHANGED
|
@@ -843,6 +843,8 @@ function resolveAnthropicPolicy(
|
|
|
843
843
|
officialEndpoint: official,
|
|
844
844
|
signingEndpoint,
|
|
845
845
|
supportsContextManagement: true,
|
|
846
|
+
supportsServerCompaction: false,
|
|
847
|
+
firstPartyProvider: false,
|
|
846
848
|
supportsOutputEffort: true,
|
|
847
849
|
disableStrictTools: isAzure,
|
|
848
850
|
disableAdaptiveThinking: false,
|
|
@@ -1021,6 +1023,7 @@ interface RuleThinking {
|
|
|
1021
1023
|
suppressWhenOff?: boolean;
|
|
1022
1024
|
supportsDisplay?: boolean;
|
|
1023
1025
|
prefixBinding?: boolean;
|
|
1026
|
+
upgradeNeutral?: boolean;
|
|
1024
1027
|
}
|
|
1025
1028
|
|
|
1026
1029
|
function readRuleThinking(axes: ResolvedAxes): RuleThinking {
|
|
@@ -1040,6 +1043,7 @@ function readRuleThinking(axes: ResolvedAxes): RuleThinking {
|
|
|
1040
1043
|
if (typeof raw.suppressWhenOff === "boolean") out.suppressWhenOff = raw.suppressWhenOff;
|
|
1041
1044
|
if (typeof raw.supportsDisplay === "boolean") out.supportsDisplay = raw.supportsDisplay;
|
|
1042
1045
|
if (typeof raw.prefixBinding === "boolean") out.prefixBinding = raw.prefixBinding;
|
|
1046
|
+
if (typeof raw.upgradeNeutral === "boolean") out.upgradeNeutral = raw.upgradeNeutral;
|
|
1043
1047
|
return out;
|
|
1044
1048
|
}
|
|
1045
1049
|
|
|
@@ -1065,7 +1069,18 @@ function resolveThinkingPolicy<TApi extends Api>(
|
|
|
1065
1069
|
axes: ResolvedAxes,
|
|
1066
1070
|
compat: CompatOf<TApi>,
|
|
1067
1071
|
): ThinkingConfig | undefined {
|
|
1068
|
-
|
|
1072
|
+
const rule = readRuleThinking(axes);
|
|
1073
|
+
const explicitThinking =
|
|
1074
|
+
spec.thinking !== undefined && Array.isArray(spec.thinking.efforts) && spec.thinking.efforts.length > 0
|
|
1075
|
+
? spec.thinking
|
|
1076
|
+
: undefined;
|
|
1077
|
+
// An explicit wire vocabulary is authoritative when discovery reports no
|
|
1078
|
+
// reasoning (e.g. Synthetic's `none`-only off-switch): reviewed KDL must
|
|
1079
|
+
// not re-expand it into an unadvertised ladder. Absent metadata is
|
|
1080
|
+
// repaired only where KDL opts in with `thinking-upgrade-neutral`
|
|
1081
|
+
// alongside an exact `thinking-efforts` ladder (the cascade upgrade for
|
|
1082
|
+
// stale source capability data); otherwise the neutral default holds.
|
|
1083
|
+
if (!spec.reasoning && (explicitThinking !== undefined || rule.upgradeNeutral !== true)) return undefined;
|
|
1069
1084
|
if (
|
|
1070
1085
|
spec.provider === "cline-pass" &&
|
|
1071
1086
|
compat !== undefined &&
|
|
@@ -1075,9 +1090,8 @@ function resolveThinkingPolicy<TApi extends Api>(
|
|
|
1075
1090
|
return undefined;
|
|
1076
1091
|
}
|
|
1077
1092
|
if (omitsWireReasoningEffort(spec.api, compat)) return undefined;
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
return fillExplicitThinking(spec, facts, compat, spec.thinking, rule);
|
|
1093
|
+
if (explicitThinking !== undefined) {
|
|
1094
|
+
return fillExplicitThinking(spec, facts, compat, explicitThinking, rule);
|
|
1081
1095
|
}
|
|
1082
1096
|
if (compat !== undefined && "trustExplicitThinkingOnly" in compat && compat.trustExplicitThinkingOnly === true) {
|
|
1083
1097
|
return undefined;
|