@oh-my-pi/pi-catalog 17.2.14 → 17.3.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 +29 -0
- package/dist/types/discovery/openai-compatible.d.ts +16 -1
- package/dist/types/identity/family.d.ts +9 -3
- package/dist/types/models.d.ts +2 -0
- package/dist/types/provider-models/openai-compat.d.ts +29 -0
- package/dist/types/types.d.ts +22 -17
- package/package.json +4 -4
- package/src/build.ts +3 -3
- package/src/compat/openai.ts +0 -6
- package/src/discovery/openai-compatible.ts +21 -4
- package/src/identity/classify.ts +29 -6
- package/src/identity/family.ts +18 -4
- package/src/model-manager.ts +13 -2
- package/src/model-thinking.ts +15 -7
- package/src/models.json +2495 -298
- package/src/models.ts +28 -14
- package/src/provider-models/bundled-references.ts +4 -2
- package/src/provider-models/openai-compat.ts +83 -1
- package/src/types.ts +24 -16
package/src/models.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { buildModel } from "./build";
|
|
2
2
|
import MODELS from "./models.json" with { type: "json" };
|
|
3
|
-
import type { Api, KnownProvider, Model, ModelSpec, Usage } from "./types";
|
|
3
|
+
import type { Api, KnownProvider, Model, ModelSpec, TokenCost, Usage } from "./types";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Static bundled model registry loaded from `models.json`.
|
|
@@ -42,13 +42,27 @@ export function getBundledModels(provider: GeneratedProvider): Model<Api>[] {
|
|
|
42
42
|
const models = getProviderModels(provider);
|
|
43
43
|
return models ? (Array.from(models.values()) as Model<Api>[]) : [];
|
|
44
44
|
}
|
|
45
|
+
function resolveTokenCost(cost: Model["cost"], promptInputTokens: number): TokenCost {
|
|
46
|
+
const longContext = cost.longContext;
|
|
47
|
+
if (!longContext) return cost;
|
|
48
|
+
return promptInputTokens > longContext.inputThreshold ? longContext : cost;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Price a prompt as fully uncached input under its active context-length tier. */
|
|
52
|
+
export function calculateUncachedInputCost(cost: Model["cost"], promptInputTokens: number): number {
|
|
53
|
+
const rates = resolveTokenCost(cost, promptInputTokens);
|
|
54
|
+
return (rates.input / 1_000_000) * promptInputTokens;
|
|
55
|
+
}
|
|
45
56
|
|
|
46
57
|
export function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage): Usage["cost"] {
|
|
47
58
|
const orchestration = usage.orchestration;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
usage.cost.
|
|
59
|
+
const promptInputTokens =
|
|
60
|
+
usage.input + usage.cacheRead + usage.cacheWrite + (orchestration?.input ?? 0) + (orchestration?.cacheRead ?? 0);
|
|
61
|
+
const rates = resolveTokenCost(model.cost, promptInputTokens);
|
|
62
|
+
usage.cost.input = (rates.input / 1000000) * (usage.input + (orchestration?.input ?? 0));
|
|
63
|
+
usage.cost.output = (rates.output / 1000000) * (usage.output + (orchestration?.output ?? 0));
|
|
64
|
+
usage.cost.cacheRead = (rates.cacheRead / 1000000) * (usage.cacheRead + (orchestration?.cacheRead ?? 0));
|
|
65
|
+
usage.cost.cacheWrite = cacheWriteCost(rates, usage);
|
|
52
66
|
usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
|
|
53
67
|
return usage.cost;
|
|
54
68
|
}
|
|
@@ -56,12 +70,12 @@ export function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage
|
|
|
56
70
|
/**
|
|
57
71
|
* Price cache-write tokens, honoring the TTL breakdown when the provider reports one.
|
|
58
72
|
*
|
|
59
|
-
* `
|
|
60
|
-
* 1.25x base input). When `usage.cttl` is present the write
|
|
61
|
-
* breakpoints
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
73
|
+
* `rates.cacheWrite` is the 5-minute write rate (Anthropic bills 5m writes at
|
|
74
|
+
* 1.25x base input). When `usage.cttl` is present the write can mix 5m and 1h
|
|
75
|
+
* breakpoints, and 1h writes bill at 2x base input, so each component is
|
|
76
|
+
* priced at its own rate instead of the flat 5m rate. Deriving 1h from
|
|
77
|
+
* `input * 2` (Anthropic's published multiplier) is model-independent and
|
|
78
|
+
* stays correct even for legacy entries whose stored
|
|
65
79
|
* `cacheWrite` scalar drifts from 1.25x input. Providers that omit `cttl`
|
|
66
80
|
* (everyone but Anthropic) keep the flat-rate calculation.
|
|
67
81
|
*
|
|
@@ -70,14 +84,14 @@ export function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage
|
|
|
70
84
|
* so any unattributed remainder is priced at the flat rate instead of being dropped:
|
|
71
85
|
* a partial or stale breakdown must never make write tokens free.
|
|
72
86
|
*/
|
|
73
|
-
function cacheWriteCost
|
|
74
|
-
const rate5m =
|
|
87
|
+
function cacheWriteCost(rates: TokenCost, usage: Usage): number {
|
|
88
|
+
const rate5m = rates.cacheWrite / 1000000;
|
|
75
89
|
const cttl = usage.cttl;
|
|
76
90
|
if (!cttl) return rate5m * usage.cacheWrite;
|
|
77
91
|
const fiveMinute = cttl.ephemeral5m ?? 0;
|
|
78
92
|
const oneHour = cttl.ephemeral1h ?? 0;
|
|
79
93
|
const residual = Math.max(0, usage.cacheWrite - fiveMinute - oneHour);
|
|
80
|
-
return rate5m * (fiveMinute + residual) + ((
|
|
94
|
+
return rate5m * (fiveMinute + residual) + ((rates.input * 2) / 1000000) * oneHour;
|
|
81
95
|
}
|
|
82
96
|
|
|
83
97
|
/**
|
|
@@ -67,9 +67,11 @@ export function createReferenceResolver<TApi extends Api>(
|
|
|
67
67
|
? () => (lazyProviderReferences ??= providerReferenceSource())
|
|
68
68
|
: () => providerReferenceSource;
|
|
69
69
|
return (modelId: string) => {
|
|
70
|
-
const
|
|
70
|
+
const providerRefs = getProviderReferences();
|
|
71
|
+
const globalRefs = getGlobalReferences();
|
|
72
|
+
const providerRef = providerRefs.get(modelId);
|
|
71
73
|
if (providerRef) return providerRef;
|
|
72
|
-
const globalRef =
|
|
74
|
+
const globalRef = globalRefs.get(modelId);
|
|
73
75
|
return globalRef ? toModelSpec(globalRef as Model<TApi>) : undefined;
|
|
74
76
|
};
|
|
75
77
|
}
|
|
@@ -866,6 +866,44 @@ export function umansModelManagerOptions(config?: UmansModelManagerConfig): Mode
|
|
|
866
866
|
// 1. OpenAI
|
|
867
867
|
// ---------------------------------------------------------------------------
|
|
868
868
|
|
|
869
|
+
const OPENAI_API_BASE_URL = "https://api.openai.com/v1";
|
|
870
|
+
export const OPENAI_GPT_56_LONG_CONTEXT_COSTS = {
|
|
871
|
+
luna: {
|
|
872
|
+
inputThreshold: 272_000,
|
|
873
|
+
input: 0.4,
|
|
874
|
+
output: 1.8,
|
|
875
|
+
cacheRead: 0.04,
|
|
876
|
+
cacheWrite: 0.5,
|
|
877
|
+
},
|
|
878
|
+
sol: {
|
|
879
|
+
inputThreshold: 272_000,
|
|
880
|
+
input: 10,
|
|
881
|
+
output: 45,
|
|
882
|
+
cacheRead: 1,
|
|
883
|
+
cacheWrite: 12.5,
|
|
884
|
+
},
|
|
885
|
+
terra: {
|
|
886
|
+
inputThreshold: 272_000,
|
|
887
|
+
input: 4,
|
|
888
|
+
output: 18,
|
|
889
|
+
cacheRead: 0.4,
|
|
890
|
+
cacheWrite: 5,
|
|
891
|
+
},
|
|
892
|
+
} as const;
|
|
893
|
+
const OPENAI_GPT_56_SOL_STANDARD_COST = {
|
|
894
|
+
input: 5,
|
|
895
|
+
output: 30,
|
|
896
|
+
cacheRead: 0.5,
|
|
897
|
+
cacheWrite: 6.25,
|
|
898
|
+
longContext: OPENAI_GPT_56_LONG_CONTEXT_COSTS.sol,
|
|
899
|
+
} as const;
|
|
900
|
+
const OPENAI_GPT_56_CYBER_STANDARD_COST = {
|
|
901
|
+
input: 12.5,
|
|
902
|
+
output: 75,
|
|
903
|
+
cacheRead: 1.25,
|
|
904
|
+
cacheWrite: 15.625,
|
|
905
|
+
} as const;
|
|
906
|
+
|
|
869
907
|
export interface OpenAIModelManagerConfig {
|
|
870
908
|
apiKey?: string;
|
|
871
909
|
baseUrl?: string;
|
|
@@ -876,7 +914,7 @@ export function openaiModelManagerOptions(config?: OpenAIModelManagerConfig): Mo
|
|
|
876
914
|
return createOpenAICompatibleModelManagerOptions({
|
|
877
915
|
api: "openai-responses",
|
|
878
916
|
providerId: "openai",
|
|
879
|
-
defaultBaseUrl:
|
|
917
|
+
defaultBaseUrl: OPENAI_API_BASE_URL,
|
|
880
918
|
config,
|
|
881
919
|
requireApiKey: true,
|
|
882
920
|
filterModel: (_entry, model, references) => isLikelyOpenAIResponsesModelId(model.id, references),
|
|
@@ -884,6 +922,50 @@ export function openaiModelManagerOptions(config?: OpenAIModelManagerConfig): Mo
|
|
|
884
922
|
});
|
|
885
923
|
}
|
|
886
924
|
|
|
925
|
+
/**
|
|
926
|
+
* Daybreak models are approval-gated first-party Responses models that are not
|
|
927
|
+
* yet present in stencil.so. Seed the documented aliases and current Cyber
|
|
928
|
+
* snapshot so fresh installs expose them without credentialed discovery.
|
|
929
|
+
*/
|
|
930
|
+
export const OPENAI_DAYBREAK_CURATED_FALLBACK_MODELS: readonly ModelSpec<"openai-responses">[] = [
|
|
931
|
+
{
|
|
932
|
+
id: "daybreak-blue-latest",
|
|
933
|
+
name: "Daybreak Blue",
|
|
934
|
+
api: "openai-responses",
|
|
935
|
+
provider: "openai",
|
|
936
|
+
baseUrl: OPENAI_API_BASE_URL,
|
|
937
|
+
reasoning: true,
|
|
938
|
+
input: ["text", "image"],
|
|
939
|
+
cost: OPENAI_GPT_56_SOL_STANDARD_COST,
|
|
940
|
+
contextWindow: 1_050_000,
|
|
941
|
+
maxTokens: 128_000,
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
id: "daybreak-red-latest",
|
|
945
|
+
name: "Daybreak Red",
|
|
946
|
+
api: "openai-responses",
|
|
947
|
+
provider: "openai",
|
|
948
|
+
baseUrl: OPENAI_API_BASE_URL,
|
|
949
|
+
reasoning: true,
|
|
950
|
+
input: ["text", "image"],
|
|
951
|
+
cost: OPENAI_GPT_56_CYBER_STANDARD_COST,
|
|
952
|
+
contextWindow: 400_000,
|
|
953
|
+
maxTokens: 128_000,
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
id: "gpt-5.6-cyber",
|
|
957
|
+
name: "GPT-5.6 Cyber",
|
|
958
|
+
api: "openai-responses",
|
|
959
|
+
provider: "openai",
|
|
960
|
+
baseUrl: OPENAI_API_BASE_URL,
|
|
961
|
+
reasoning: true,
|
|
962
|
+
input: ["text", "image"],
|
|
963
|
+
cost: OPENAI_GPT_56_CYBER_STANDARD_COST,
|
|
964
|
+
contextWindow: 400_000,
|
|
965
|
+
maxTokens: 128_000,
|
|
966
|
+
},
|
|
967
|
+
];
|
|
968
|
+
|
|
887
969
|
/** First-party gpt-5.6 SKUs that accept `reasoning: { mode: "pro" }` on the Responses APIs. */
|
|
888
970
|
const OPENAI_PRO_REASONING_BASE_IDS: Record<string, true> = {
|
|
889
971
|
"gpt-5.6-luna": true,
|
package/src/types.ts
CHANGED
|
@@ -155,6 +155,7 @@ export type OpenAIReasoningFormat = "openai" | "openrouter" | "zai" | "kimi" | "
|
|
|
155
155
|
export type OpenAIReasoningDisableMode =
|
|
156
156
|
| "omit"
|
|
157
157
|
| "lowest-effort"
|
|
158
|
+
| "none-effort"
|
|
158
159
|
| "openrouter-enabled-false"
|
|
159
160
|
| "zai-thinking-disabled"
|
|
160
161
|
| "qwen-enable-thinking-false"
|
|
@@ -190,13 +191,6 @@ export interface OpenAICompat {
|
|
|
190
191
|
reasoningEffortMap?: Partial<Record<Effort, string>>;
|
|
191
192
|
/** Whether the provider supports `stream_options: { include_usage: true }` for token usage in streaming responses. Default: true. */
|
|
192
193
|
supportsUsageInStreaming?: boolean;
|
|
193
|
-
/**
|
|
194
|
-
* Enable the Gemini thinking-loop guard (pi-ai stream layer) for this model.
|
|
195
|
-
* Defaults to true when the model id classifies as the gemini family. Set
|
|
196
|
-
* explicitly to cover an opaque OpenAI-compat proxy alias (e.g. `my-model`)
|
|
197
|
-
* that routes to Gemini, or to false to opt a gemini-family id out.
|
|
198
|
-
*/
|
|
199
|
-
enableGeminiThinkingLoopGuard?: boolean;
|
|
200
194
|
/** Which field to use for max tokens. Default: auto-detected from URL. */
|
|
201
195
|
maxTokensField?: "max_completion_tokens" | "max_tokens";
|
|
202
196
|
/** Whether tool results require the `name` field. Default: auto-detected from URL. */
|
|
@@ -627,8 +621,6 @@ export interface ResolvedOpenAISharedCompat {
|
|
|
627
621
|
isOpenRouterHost: boolean;
|
|
628
622
|
/** Whether this endpoint needs a max-token field even when caller did not set one. */
|
|
629
623
|
alwaysSendMaxTokens: boolean;
|
|
630
|
-
/** See {@link OpenAICompat.enableGeminiThinkingLoopGuard}. Set by the builder from the family classifier. */
|
|
631
|
-
enableGeminiThinkingLoopGuard?: boolean;
|
|
632
624
|
openRouterRouting?: OpenAICompat["openRouterRouting"];
|
|
633
625
|
/** Provider-specific wire model-id transform applied to the base id. */
|
|
634
626
|
wireModelIdMode: "raw" | "firepass" | "fireworks" | "openrouter";
|
|
@@ -697,7 +689,6 @@ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat &
|
|
|
697
689
|
| "thinkingKeep"
|
|
698
690
|
| "strictResponsesPairing"
|
|
699
691
|
| "supportsImageDetailOriginal"
|
|
700
|
-
| "enableGeminiThinkingLoopGuard"
|
|
701
692
|
| "whenThinking"
|
|
702
693
|
>
|
|
703
694
|
> & {
|
|
@@ -819,6 +810,28 @@ export interface RemoteCompactionConfig<TApi extends Api = Api> {
|
|
|
819
810
|
model?: string;
|
|
820
811
|
}
|
|
821
812
|
|
|
813
|
+
/** Per-million-token rates for one model pricing tier. */
|
|
814
|
+
export interface TokenCost {
|
|
815
|
+
input: number;
|
|
816
|
+
output: number;
|
|
817
|
+
cacheRead: number;
|
|
818
|
+
cacheWrite: number;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Rates applied to the full request when its prompt exceeds `inputThreshold`.
|
|
823
|
+
* Prompt input is the sum of uncached, cached-read, cache-write, and
|
|
824
|
+
* provider-orchestration input tokens.
|
|
825
|
+
*/
|
|
826
|
+
export interface LongContextTokenCost extends TokenCost {
|
|
827
|
+
inputThreshold: number;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
/** Base token rates plus an optional long-context tier. */
|
|
831
|
+
export interface ModelCost extends TokenCost {
|
|
832
|
+
longContext?: LongContextTokenCost;
|
|
833
|
+
}
|
|
834
|
+
|
|
822
835
|
// Model interface for the unified model system
|
|
823
836
|
export interface Model<TApi extends Api = Api> {
|
|
824
837
|
id: string;
|
|
@@ -864,12 +877,7 @@ export interface Model<TApi extends Api = Api> {
|
|
|
864
877
|
gitlabDuoWorkflowRootNamespaceId?: string;
|
|
865
878
|
/** Cursor `max_mode` request flag returned by `GetUsableModels` for premium models that require max mode. */
|
|
866
879
|
cursorMaxMode?: boolean;
|
|
867
|
-
cost:
|
|
868
|
-
input: number; // $/million tokens
|
|
869
|
-
output: number; // $/million tokens
|
|
870
|
-
cacheRead: number; // $/million tokens
|
|
871
|
-
cacheWrite: number; // $/million tokens
|
|
872
|
-
};
|
|
880
|
+
cost: ModelCost;
|
|
873
881
|
/** Premium Copilot requests charged per user-initiated request (defaults to 1). */
|
|
874
882
|
premiumMultiplier?: number;
|
|
875
883
|
contextWindow: number | null;
|