@xiaoso/dsh-tool-plus 0.1.16 → 0.1.17-beta.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/lib/{abort-DZ54CaKU.mjs → abort-BTblp0Rt.mjs} +2 -2
- package/lib/{alibaba-coding-plan-DODpkcqi.mjs → alibaba-coding-plan-t3R4YKCB.mjs} +3 -3
- package/lib/{alibaba-token-plan-C6lpKCda.mjs → alibaba-token-plan-CO4djG1y.mjs} +4 -4
- package/lib/{alibaba-token-plan-CHGyWOfX.mjs → alibaba-token-plan-CUjYJX0-.mjs} +1 -1
- package/lib/{anthropic-Dv_GGX6g.mjs → anthropic-nf7w6so1.mjs} +48 -21
- package/lib/{api-key-validation-MnMf_ihX.mjs → api-key-validation-C_tZ7Y9a.mjs} +2 -2
- package/lib/behavior-BwvTUtag.mjs +111 -0
- package/lib/{browser-render-BZXt548F.mjs → browser-render-BQaEVK_n.mjs} +4 -4
- package/lib/{reference-CtvM4zLU.mjs → bundled-references-CrQ4dQcT.mjs} +57 -4
- package/lib/cascade-BWjRTD1q.mjs +30265 -0
- package/lib/{cline-pass-BT9CBEOj.mjs → cline-pass-Bjm-O8GG.mjs} +2 -2
- package/lib/cloudflare-CKXRJ0l9.mjs +37 -0
- package/lib/{cloudflare-ai-gateway-DReN6ohJ.mjs → cloudflare-ai-gateway-BpnBSjwV.mjs} +8 -4
- package/lib/cloudflare-workers-ai-odj9XswL.mjs +32 -0
- package/lib/collapse-_nkb2dn7.mjs +1945 -0
- package/lib/{coreweave-C82HrLpb.mjs → coreweave-CGDZOD8-.mjs} +1 -1
- package/lib/{coreweave-C68UgRQO.mjs → coreweave-DwffcgW5.mjs} +4 -4
- package/lib/cursor-BgOuV7Qf.mjs +794 -0
- package/lib/{cursor-_gHHq-Dq.mjs → cursor-CF1iHHbv.mjs} +68 -19
- package/lib/{cursor-proto-Cr_WEMuv.mjs → cursor-proto-BuNTjX3L.mjs} +823 -23
- package/lib/{devin-QpfTSl9H.mjs → devin-7OEeEb80.mjs} +112 -31
- package/lib/{devin-proto-DYhp4Ty6.mjs → devin-proto-C-QreeAv.mjs} +71 -5
- package/lib/{dom-DG3sPESc.mjs → dom-BmbZv4v9.mjs} +598 -182
- package/lib/{error-O63pC8zg.mjs → error-8LVo7tug.mjs} +725 -104
- package/lib/factory-droid-ChhmsGWb.mjs +71 -0
- package/lib/{fs-promises-shim-B2YFWkcd.mjs → fs-promises-shim-CANAxFWh.mjs} +10 -1
- package/lib/{github-copilot-BMEcw8N1.mjs → github-copilot-QwevdT30.mjs} +4 -4
- package/lib/{github-copilot-headers-DnjGEbko.mjs → github-copilot-headers-CAUZ0rUD.mjs} +138 -26
- package/lib/{gitlab-duo-DnHqJjFY.mjs → gitlab-duo-DigV7k_o.mjs} +2 -2
- package/lib/{google-antigravity-B1mSckrK.mjs → google-antigravity-D-oe0r8A.mjs} +6 -7
- package/lib/{google-gemini-cli-DJwThCCn.mjs → google-gemini-cli-CQBHgGJT.mjs} +5 -6
- package/lib/{google-oauth-shared-BctLpVUN.mjs → google-oauth-shared-CvgVIUwJ.mjs} +2 -2
- package/lib/google-validation-CdvRj4ec.mjs +126 -0
- package/lib/id-EJwVLDHE.mjs +2548 -0
- package/lib/index.mjs +248 -258
- package/lib/{kilo-BEgEwMJQ.mjs → kilo-5r6OffCa.mjs} +2 -2
- package/lib/{kimi-T9NldEIJ.mjs → kimi-DOOtbXmm.mjs} +9 -10
- package/lib/{launch-BIWNyrBB.mjs → launch-DkAjib7h.mjs} +1 -1
- package/lib/{markit-Dvp2JPdT.mjs → markit-CCcyeAds.mjs} +359 -140
- package/lib/{models-DnXMYGcJ.mjs → models-DCpDT_im.mjs} +199203 -112275
- package/lib/{muse-code-CNvqqAp6.mjs → muse-code-CYf8zj_B.mjs} +5 -5
- package/lib/{openai-codex-D5-CyTxa.mjs → openai-codex-Cj-TvSFh.mjs} +13 -10
- package/lib/{perplexity-A2PEoGaC.mjs → perplexity-Dh_Qgsmx.mjs} +68 -25
- package/lib/{pkce-BYjmugmw.mjs → pkce-DO-jBJLV.mjs} +1 -1
- package/lib/pricing-DusBEhwm.mjs +593 -0
- package/lib/{readability-uGhqb4GC.mjs → readability-XHK0o3bv.mjs} +287 -27
- package/lib/{scrapers-C1ujjV8k.mjs → scrapers-B6PADOVm.mjs} +13 -13
- package/lib/slugify-ynYWBIA5.mjs +11 -0
- package/lib/snowflake-B_jap6lz.mjs +666 -0
- package/lib/snowflake-Cu1ZyOp6.mjs +151 -0
- package/lib/{src-AELUUb5U.mjs → src-BhinCSpi.mjs} +1172 -458
- package/lib/{stream-AVOoe5Hj.mjs → stream-D2ivg3GH.mjs} +3740 -5311
- package/lib/{turndown-D6fof1OX.mjs → turndown-Vya8SavL.mjs} +82 -30
- package/lib/types/tools/hashline/native/index.d.ts +2 -2
- package/lib/types/tools/hashline/native/policy.d.ts +19 -21
- package/lib/types/tools/omp/session/agent-storage.d.ts +3 -3
- package/lib/types/tools/shared/bun-named-shim.d.ts +5 -0
- package/lib/{types-BLrLohwK.mjs → types-tH1v9uRm.mjs} +2 -2
- package/lib/{utils-cZX3f_Ls.mjs → utils-C_Ncya1r.mjs} +1737 -509
- package/lib/utils-D2tK38xq.mjs +34006 -0
- package/lib/{utils-I4I8azHN.mjs → utils-DrDwmNtu.mjs} +8 -3
- package/lib/{xai-oauth-CbeldUSV.mjs → xai-oauth-DLLzX6my.mjs} +4 -4
- package/lib/{xiaomi-Dl3VSs04.mjs → xiaomi-CqK-KivK.mjs} +2 -2
- package/lib/{zai-FyjGSypr.mjs → zai-DoJ2xPIH.mjs} +2 -2
- package/lib/{zip-DRrycScC.mjs → zip-DG1mUV6X.mjs} +1 -1
- package/package.json +8 -8
- package/lib/amazon-bedrock-Dx0rr9dY.mjs +0 -996
- package/lib/anthropic-ClCw0PV_.mjs +0 -3624
- package/lib/anthropic-wire-lbGAFzYb.mjs +0 -927
- package/lib/azure-openai-responses-WE_bgFWp.mjs +0 -285
- package/lib/bundled-references-DY3EJxZV.mjs +0 -56
- package/lib/cloudflare-ai-gateway-CrMa97Ap.mjs +0 -44
- package/lib/collapse-CkMNRNr7.mjs +0 -2304
- package/lib/cursor-C6jaIJDg.mjs +0 -283
- package/lib/cursor-D-XZYDf_.mjs +0 -4544
- package/lib/deterministic-id-CUEIMSqR.mjs +0 -17
- package/lib/devin-ExGIghmx.mjs +0 -69
- package/lib/devin-u0ljw5P6.mjs +0 -628
- package/lib/effort-BdtQMN-_.mjs +0 -23
- package/lib/event-stream-BKEtb45Y.mjs +0 -167
- package/lib/gemini-headers-Co9cVvex.mjs +0 -54
- package/lib/google-auth-qAN-6DMW.mjs +0 -232
- package/lib/google-gemini-cli-B2Aw1S5w.mjs +0 -844
- package/lib/google-lTxuq28n.mjs +0 -38
- package/lib/google-shared-Y01j9xOr.mjs +0 -856
- package/lib/google-validation-BEkNs-Bx.mjs +0 -18
- package/lib/google-vertex-DcM-FRC5.mjs +0 -99
- package/lib/hosts-00rjRzUD.mjs +0 -203
- package/lib/id-AL5obQzR.mjs +0 -71
- package/lib/idle-iterator-D0ZXEcUq.mjs +0 -366
- package/lib/ollama-6R0oXZks.mjs +0 -574
- package/lib/openai-codex-responses-C8bnBWOe.mjs +0 -3232
- package/lib/openai-completions-DNr3mUsn.mjs +0 -1430
- package/lib/openai-configuration-update-xMYUjaK_.mjs +0 -150
- package/lib/openai-reasoning-fallback-Ju-5pSR8.mjs +0 -380
- package/lib/openai-responses-CjpafAEr.mjs +0 -861
- package/lib/protobuf-BMgDYu_U.mjs +0 -717
- package/lib/provider-response-SqKSkkUc.mjs +0 -22
- package/lib/proxy-DxvCQOCA.mjs +0 -230
- package/lib/request-debug-BwPOqN_j.mjs +0 -183
- package/lib/sanitize-text-BCf5KmCf.mjs +0 -33
- package/lib/sse-debug-B-tkLCPW.mjs +0 -11
- package/lib/stream-markup-healing-CN3RsqG9.mjs +0 -267
- package/lib/strict-tool-validation-CBTz1dAA.mjs +0 -105
- package/lib/taxonomy-DSIM99rS.mjs +0 -15392
- package/lib/thinking-ngMwf_1Y.mjs +0 -336
- package/lib/type-guards-CttAANEx.mjs +0 -11
- package/lib/utils-CE3DSebh.mjs +0 -11763
- package/lib/vision-guard-BCpXWUj3.mjs +0 -77
|
@@ -0,0 +1,1945 @@
|
|
|
1
|
+
import { installBunShim as __installBunShim } from "./bun-shim.mjs";
|
|
2
|
+
__installBunShim();
|
|
3
|
+
import "./src-BhinCSpi.mjs";
|
|
4
|
+
import { c as compareRevision, d as parseRevisionConstraint, h as isRecord, p as revisionSatisfies, u as parseRevision } from "./cascade-BWjRTD1q.mjs";
|
|
5
|
+
import { L as THINKING_EFFORTS, h as MODEL_KINDS, s as resolveModelPolicy, t as bareModelId } from "./id-EJwVLDHE.mjs";
|
|
6
|
+
import { t as cleanModelName } from "./utils-DrDwmNtu.mjs";
|
|
7
|
+
import { a as dueEffectiveRate, d as collapseVocabulary, l as classifyModel, n as NO_RECURRING_TARIFF, o as materializeTimeBasedCost, p as stripThinkingVariantSuffix, r as applyDueDatedCostCard, s as parseDatedCostCards, t as EARLIEST_EFFECTIVE_FROM, u as collapseVariantId } from "./pricing-DusBEhwm.mjs";
|
|
8
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/model-tokenizer.ts
|
|
9
|
+
const MAX_TOKENIZER_CACHE_ENTRIES = 2048;
|
|
10
|
+
const modelTokenizerCache = /* @__PURE__ */ new Map();
|
|
11
|
+
function revisionAtLeast$1(revision, floor) {
|
|
12
|
+
if (revision === void 0) return false;
|
|
13
|
+
const parsedRevision = parseRevision(revision);
|
|
14
|
+
const parsedFloor = parseRevision(floor);
|
|
15
|
+
return parsedRevision !== void 0 && parsedFloor !== void 0 && compareRevision(parsedRevision, parsedFloor) >= 0;
|
|
16
|
+
}
|
|
17
|
+
function claudeTokenizer(identity) {
|
|
18
|
+
if (identity.class !== "anthropic") return void 0;
|
|
19
|
+
if (identity.family === "opus") {
|
|
20
|
+
if (revisionAtLeast$1(identity.revision, "5")) return "claude-v5";
|
|
21
|
+
if (revisionAtLeast$1(identity.revision, "4.7")) return "claude-v47";
|
|
22
|
+
return "claude-v3";
|
|
23
|
+
}
|
|
24
|
+
if (identity.family === "sonnet" || identity.family === "fable" || identity.family === "mythos") return revisionAtLeast$1(identity.revision, "5") ? "claude-v5-sonnet" : "claude-v3";
|
|
25
|
+
if (identity.family === "haiku" && revisionAtLeast$1(identity.revision, "5.5")) return "claude-v5-sonnet";
|
|
26
|
+
return "claude-v3";
|
|
27
|
+
}
|
|
28
|
+
function qwenTokenizer(identity) {
|
|
29
|
+
return identity.class === "qwen" && revisionAtLeast$1(identity.revision, "3.5") ? "qwen3" : void 0;
|
|
30
|
+
}
|
|
31
|
+
function deepSeekTokenizer(identity) {
|
|
32
|
+
return identity.class === "deepseek" ? "deepseek-v3" : void 0;
|
|
33
|
+
}
|
|
34
|
+
function kimiTokenizer(identity) {
|
|
35
|
+
return identity.class === "kimi" ? "kimi-k2" : void 0;
|
|
36
|
+
}
|
|
37
|
+
function glmTokenizer(identity) {
|
|
38
|
+
return identity.class === "glm" && revisionAtLeast$1(identity.revision, "5") ? "glm5" : void 0;
|
|
39
|
+
}
|
|
40
|
+
function openAITokenizer(identity) {
|
|
41
|
+
return identity.class === "openai" && revisionAtLeast$1(identity.revision, "5") ? "o200k" : void 0;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve the exact locally embedded tokenizer for a canonical model id.
|
|
45
|
+
*
|
|
46
|
+
* This is catalog policy, not a runtime caller heuristic: [`buildModel`](./build.ts)
|
|
47
|
+
* materializes the result as `Model.tokenizer`; consumers read that property.
|
|
48
|
+
*/
|
|
49
|
+
function resolveModelTokenizer(modelId, provider = "") {
|
|
50
|
+
const cacheKey = `${provider}\0${modelId}`;
|
|
51
|
+
const cached = modelTokenizerCache.get(cacheKey);
|
|
52
|
+
if (cached !== void 0) return cached ?? void 0;
|
|
53
|
+
const identity = classifyModel(provider, bareModelId(modelId), { lenient: true });
|
|
54
|
+
const tokenizer = claudeTokenizer(identity) ?? qwenTokenizer(identity) ?? deepSeekTokenizer(identity) ?? kimiTokenizer(identity) ?? glmTokenizer(identity) ?? openAITokenizer(identity);
|
|
55
|
+
if (modelTokenizerCache.size === MAX_TOKENIZER_CACHE_ENTRIES) modelTokenizerCache.clear();
|
|
56
|
+
modelTokenizerCache.set(cacheKey, tokenizer ?? null);
|
|
57
|
+
return tokenizer;
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/build.ts
|
|
61
|
+
/**
|
|
62
|
+
* The single Model constructor. Resolution runs through the compat engine
|
|
63
|
+
* (`compat/resolve`): identity classification, cascade-rule axes, host
|
|
64
|
+
* detection, and spec overrides materialize exactly once per spec.
|
|
65
|
+
*
|
|
66
|
+
* Request handlers read fields — they never detect, parse ids, or allocate
|
|
67
|
+
* compat per request.
|
|
68
|
+
*/
|
|
69
|
+
function numberField(source, key) {
|
|
70
|
+
const value = Reflect.get(source, key);
|
|
71
|
+
return typeof value === "number" ? value : void 0;
|
|
72
|
+
}
|
|
73
|
+
/** Narrow an unknown compiled-axis payload to an object payload. */
|
|
74
|
+
function objectPayload(value) {
|
|
75
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
76
|
+
}
|
|
77
|
+
/** Narrow a compiled `input-modalities` axis value to the model input union. */
|
|
78
|
+
function isInputModalities(value) {
|
|
79
|
+
return Array.isArray(value) && value.every((entry) => entry === "text" || entry === "image");
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Applies resolved catalog-data axes onto the model: reviewed metadata
|
|
83
|
+
* corrections (`cost-patch`, `limits-patch`, `long-context-cost`,
|
|
84
|
+
* `context-window-floor`) overwrite upstream values; selection metadata
|
|
85
|
+
* (`priority`, `apply-patch-tool-type`, `service-tier-cost`,
|
|
86
|
+
* `requires-cursor-tool-schema-projection`, `requires-tool-result-image-hoisting`,
|
|
87
|
+
* `supports-assistant-prefill`) is rule-owned; `context-promotion-target` fills
|
|
88
|
+
* only when the spec left it unset.
|
|
89
|
+
*/
|
|
90
|
+
function applyCatalogAssignments(model, catalog) {
|
|
91
|
+
const kind = MODEL_KINDS.find((value) => value === catalog.kind);
|
|
92
|
+
if (kind !== void 0) model.kind = kind;
|
|
93
|
+
if (catalog.contextWindowAuthoritative === true) model.contextWindowAuthoritative = true;
|
|
94
|
+
else delete model.contextWindowAuthoritative;
|
|
95
|
+
if (catalog.longContextWindowUncapped === true) model.longContextWindowUncapped = true;
|
|
96
|
+
else delete model.longContextWindowUncapped;
|
|
97
|
+
const webSearch = catalog.webSearch;
|
|
98
|
+
if (webSearch === "gemini" || webSearch === "anthropic" || webSearch === "codex" || webSearch === "xai" || webSearch === "openrouter" || webSearch === "openai") model.webSearch = webSearch;
|
|
99
|
+
if (typeof catalog.webSearchModel === "string") model.webSearchModel = catalog.webSearchModel;
|
|
100
|
+
if (catalog.hostedImage === true) model.hostedImage = true;
|
|
101
|
+
else if (catalog.hostedImage === false) delete model.hostedImage;
|
|
102
|
+
if (typeof catalog.imageModel === "string") model.imageModel = catalog.imageModel;
|
|
103
|
+
else if (catalog.imageModel === false) delete model.imageModel;
|
|
104
|
+
const serviceTierCost = objectPayload(catalog.serviceTierCost);
|
|
105
|
+
if (serviceTierCost !== void 0) {
|
|
106
|
+
const flex = numberField(serviceTierCost, "flex");
|
|
107
|
+
const priorityTier = numberField(serviceTierCost, "priority");
|
|
108
|
+
const ultrafast = numberField(serviceTierCost, "ultrafast");
|
|
109
|
+
model.serviceTierCost = {
|
|
110
|
+
...flex !== void 0 && { flex },
|
|
111
|
+
...priorityTier !== void 0 && { priority: priorityTier },
|
|
112
|
+
...ultrafast !== void 0 && { ultrafast }
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const priority = catalog.priority;
|
|
116
|
+
if (typeof priority === "number") model.priority = priority;
|
|
117
|
+
const promptCache = objectPayload(catalog.promptCache);
|
|
118
|
+
if (promptCache !== void 0) {
|
|
119
|
+
const short = numberField(promptCache, "short");
|
|
120
|
+
const long = numberField(promptCache, "long");
|
|
121
|
+
model.promptCache = {
|
|
122
|
+
...short !== void 0 && { short },
|
|
123
|
+
...long !== void 0 && { long }
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const applyPatchToolType = catalog.applyPatchToolType;
|
|
127
|
+
if (applyPatchToolType === "freeform" || applyPatchToolType === "function") model.applyPatchToolType = applyPatchToolType;
|
|
128
|
+
const editPromptVariant = catalog.editPromptVariant;
|
|
129
|
+
if (editPromptVariant === "full" || editPromptVariant === "compact") model.editPromptVariant = editPromptVariant;
|
|
130
|
+
const pricingStatus = catalog.pricingStatus;
|
|
131
|
+
if (pricingStatus === "free" || pricingStatus === "included" || pricingStatus === "variable" || pricingStatus === "unknown") model.pricingStatus = pricingStatus;
|
|
132
|
+
if (catalog.requiresCursorToolSchemaProjection === true) model.requiresCursorToolSchemaProjection = true;
|
|
133
|
+
else delete model.requiresCursorToolSchemaProjection;
|
|
134
|
+
if (catalog.toolSchemasInContext === false) model.toolSchemasInContext = false;
|
|
135
|
+
else delete model.toolSchemasInContext;
|
|
136
|
+
if (catalog.requiresToolResultImageHoisting === true) model.requiresToolResultImageHoisting = true;
|
|
137
|
+
else delete model.requiresToolResultImageHoisting;
|
|
138
|
+
if (catalog.supportsAssistantPrefill === true) model.supportsAssistantPrefill = true;
|
|
139
|
+
else delete model.supportsAssistantPrefill;
|
|
140
|
+
if (typeof catalog.omitMaxOutputTokens === "boolean" && model.omitMaxOutputTokens === void 0) model.omitMaxOutputTokens = catalog.omitMaxOutputTokens;
|
|
141
|
+
const contextPromotionTarget = catalog.contextPromotionTarget;
|
|
142
|
+
if (typeof contextPromotionTarget === "string" && model.contextPromotionTarget === void 0) model.contextPromotionTarget = contextPromotionTarget;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The row's corrected price card at `now`: `cost-patch`, then `cost-fallback`
|
|
146
|
+
* (each with its dated card due at `now`), then the long-context tier and
|
|
147
|
+
* cache-rate derivations, all from the upstream card.
|
|
148
|
+
*/
|
|
149
|
+
function correctedCost(upstream, catalog, cards, now) {
|
|
150
|
+
let cost = { ...upstream };
|
|
151
|
+
const upstreamCard = upstream.timeBased?.effectiveRates?.[0]?.effectiveFrom === -864e13 ? dueEffectiveRate(upstream.timeBased, now) : void 0;
|
|
152
|
+
if (upstreamCard !== void 0) {
|
|
153
|
+
const { effectiveFrom: _effectiveFrom, ...card } = upstreamCard;
|
|
154
|
+
const { longContext: _longContext, ...base } = cost;
|
|
155
|
+
cost = {
|
|
156
|
+
...base,
|
|
157
|
+
...card
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const patch = objectPayload(catalog.costPatch);
|
|
161
|
+
if (patch !== void 0) {
|
|
162
|
+
const input = numberField(patch, "input");
|
|
163
|
+
if (input !== void 0) cost.input = input;
|
|
164
|
+
const output = numberField(patch, "output");
|
|
165
|
+
if (output !== void 0) cost.output = output;
|
|
166
|
+
const cacheRead = numberField(patch, "cacheRead");
|
|
167
|
+
if (cacheRead !== void 0) cost.cacheRead = cacheRead;
|
|
168
|
+
const cacheWrite = numberField(patch, "cacheWrite");
|
|
169
|
+
if (cacheWrite !== void 0) cost.cacheWrite = cacheWrite;
|
|
170
|
+
applyDueDatedCostCard(cost, cards.patch, now);
|
|
171
|
+
}
|
|
172
|
+
const fallback = objectPayload(catalog.costFallback);
|
|
173
|
+
if (fallback !== void 0) {
|
|
174
|
+
if (!(cost.input !== 0 || cost.output !== 0 || cost.cacheRead !== 0 || cost.cacheWrite !== 0)) {
|
|
175
|
+
const input = numberField(fallback, "input");
|
|
176
|
+
if (input !== void 0) cost.input = input;
|
|
177
|
+
const output = numberField(fallback, "output");
|
|
178
|
+
if (output !== void 0) cost.output = output;
|
|
179
|
+
const cacheRead = numberField(fallback, "cacheRead");
|
|
180
|
+
if (cacheRead !== void 0) cost.cacheRead = cacheRead;
|
|
181
|
+
const cacheWrite = numberField(fallback, "cacheWrite");
|
|
182
|
+
if (cacheWrite !== void 0) cost.cacheWrite = cacheWrite;
|
|
183
|
+
applyDueDatedCostCard(cost, cards.fallback, now);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const longContext = objectPayload(catalog.longContext);
|
|
187
|
+
if (longContext !== void 0) {
|
|
188
|
+
const inputThreshold = numberField(longContext, "inputThreshold");
|
|
189
|
+
const inclusive = Reflect.get(longContext, "inputThresholdInclusive") === true;
|
|
190
|
+
const multiplier = numberField(longContext, "multiplier");
|
|
191
|
+
const input = numberField(longContext, "input");
|
|
192
|
+
const output = numberField(longContext, "output");
|
|
193
|
+
const cacheRead = numberField(longContext, "cacheRead");
|
|
194
|
+
const cacheWrite = numberField(longContext, "cacheWrite");
|
|
195
|
+
const hasTokenPrice = cost.input !== 0 || cost.output !== 0 || cost.cacheRead !== 0 || cost.cacheWrite !== 0;
|
|
196
|
+
if (inputThreshold !== void 0 && multiplier !== void 0 && hasTokenPrice) cost = {
|
|
197
|
+
...cost,
|
|
198
|
+
longContext: {
|
|
199
|
+
inputThreshold,
|
|
200
|
+
...inclusive && { inputThresholdInclusive: true },
|
|
201
|
+
input: cost.input * multiplier,
|
|
202
|
+
output: cost.output * (numberField(longContext, "outputMultiplier") ?? multiplier),
|
|
203
|
+
cacheRead: cost.cacheRead * multiplier,
|
|
204
|
+
cacheWrite: cost.cacheWrite * multiplier
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
else if (inputThreshold !== void 0 && input !== void 0 && output !== void 0 && cacheRead !== void 0 && cacheWrite !== void 0) cost = {
|
|
208
|
+
...cost,
|
|
209
|
+
longContext: {
|
|
210
|
+
inputThreshold,
|
|
211
|
+
input,
|
|
212
|
+
output,
|
|
213
|
+
cacheRead,
|
|
214
|
+
cacheWrite
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
if (catalog.cacheReadAtInputRate === true) {
|
|
219
|
+
const { longContext } = cost;
|
|
220
|
+
cost = {
|
|
221
|
+
...cost,
|
|
222
|
+
cacheRead: cost.input,
|
|
223
|
+
...longContext && { longContext: {
|
|
224
|
+
...longContext,
|
|
225
|
+
cacheRead: longContext.input
|
|
226
|
+
} }
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
const cacheWriteRate = catalog.cacheWriteRate;
|
|
230
|
+
if (typeof cacheWriteRate === "number") {
|
|
231
|
+
const { longContext } = cost;
|
|
232
|
+
cost = {
|
|
233
|
+
...cost,
|
|
234
|
+
cacheWrite: cost.input * cacheWriteRate,
|
|
235
|
+
...longContext && { longContext: {
|
|
236
|
+
...longContext,
|
|
237
|
+
cacheWrite: longContext.input * cacheWriteRate
|
|
238
|
+
} }
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
return cost;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Every price period the dated `cost-patch`/`cost-fallback` cards define, for
|
|
245
|
+
* request-time selection (`calculateUsageCost`): a row built before a change
|
|
246
|
+
* still bills requests after it at the new price, and a leading card keeps
|
|
247
|
+
* earlier requests at the old one on rows built after it. Undefined when no
|
|
248
|
+
* card changes the price (no cards, or a fallback the upstream price outranks).
|
|
249
|
+
*/
|
|
250
|
+
function scheduledRates(upstream, catalog, cards) {
|
|
251
|
+
const dates = [...cards.patch, ...cards.fallback].map((card) => card.effectiveFrom).sort((a, b) => a - b);
|
|
252
|
+
if (dates.length === 0) return void 0;
|
|
253
|
+
const periods = [];
|
|
254
|
+
let previousPrice;
|
|
255
|
+
for (const effectiveFrom of [EARLIEST_EFFECTIVE_FROM, ...dates]) {
|
|
256
|
+
const { input, output, cacheRead, cacheWrite, longContext } = correctedCost(upstream, catalog, cards, effectiveFrom);
|
|
257
|
+
const price = {
|
|
258
|
+
input,
|
|
259
|
+
output,
|
|
260
|
+
cacheRead,
|
|
261
|
+
cacheWrite,
|
|
262
|
+
...longContext && { longContext }
|
|
263
|
+
};
|
|
264
|
+
const key = JSON.stringify(price);
|
|
265
|
+
if (key === previousPrice) continue;
|
|
266
|
+
previousPrice = key;
|
|
267
|
+
periods.push({
|
|
268
|
+
effectiveFrom,
|
|
269
|
+
...price
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return periods.length > 1 ? periods : void 0;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Applies reviewed catalog-data value corrections (`cost-patch`,
|
|
276
|
+
* `cache-read-at-input-rate`, `cache-write-rate`, `limits-patch`,
|
|
277
|
+
* `long-context-cost`, `context-window-floor`, `input-modalities`) onto an
|
|
278
|
+
* upstream-sourced spec. Applied by
|
|
279
|
+
* `buildModel` to every upstream-sourced spec; user-authored overrides are
|
|
280
|
+
* recomposed after building by the override applicators, so explicit user
|
|
281
|
+
* limits and pricing still win.
|
|
282
|
+
*/
|
|
283
|
+
function applyCatalogCorrections(model, catalog) {
|
|
284
|
+
const upstream = model.cost;
|
|
285
|
+
const cards = {
|
|
286
|
+
patch: parseDatedCostCards(catalog.costPatch, "cost-patch"),
|
|
287
|
+
fallback: parseDatedCostCards(catalog.costFallback, "cost-fallback")
|
|
288
|
+
};
|
|
289
|
+
model.cost = correctedCost(upstream, catalog, cards, Date.now());
|
|
290
|
+
const recurring = catalog.timeBased === void 0 ? void 0 : materializeTimeBasedCost(catalog.timeBased);
|
|
291
|
+
const dated = scheduledRates(upstream, catalog, cards);
|
|
292
|
+
if (dated !== void 0) {
|
|
293
|
+
if (recurring?.effectiveRates !== void 0) throw new Error("Dated cost-patch/cost-fallback effective-rates cannot combine with time-based-cost effective-rates");
|
|
294
|
+
model.cost = {
|
|
295
|
+
...model.cost,
|
|
296
|
+
timeBased: {
|
|
297
|
+
...recurring ?? NO_RECURRING_TARIFF,
|
|
298
|
+
effectiveRates: dated
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
} else if (recurring !== void 0) model.cost = {
|
|
302
|
+
...model.cost,
|
|
303
|
+
timeBased: recurring
|
|
304
|
+
};
|
|
305
|
+
const limitsPatch = objectPayload(catalog.limitsPatch);
|
|
306
|
+
if (limitsPatch !== void 0) {
|
|
307
|
+
const contextWindow = numberField(limitsPatch, "contextWindow");
|
|
308
|
+
if (contextWindow !== void 0) model.contextWindow = contextWindow;
|
|
309
|
+
const maxTokens = numberField(limitsPatch, "maxTokens");
|
|
310
|
+
if (maxTokens !== void 0) model.maxTokens = maxTokens;
|
|
311
|
+
}
|
|
312
|
+
const maxTokensFallback = catalog.maxTokensFallback;
|
|
313
|
+
if (typeof maxTokensFallback === "number" && model.maxTokens === null) model.maxTokens = maxTokensFallback;
|
|
314
|
+
const maxTokensCeiling = catalog.maxTokensCeiling;
|
|
315
|
+
if (typeof maxTokensCeiling === "number" && model.maxTokens !== null && model.maxTokens > maxTokensCeiling) model.maxTokens = maxTokensCeiling;
|
|
316
|
+
const contextWindowFloor = catalog.contextWindowFloor;
|
|
317
|
+
if (typeof contextWindowFloor === "number") model.contextWindow = Math.max(model.contextWindow ?? 0, contextWindowFloor);
|
|
318
|
+
const inputModalities = catalog.inputModalities;
|
|
319
|
+
if (isInputModalities(inputModalities)) model.input = inputModalities;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Direct first-party OpenAI Responses endpoints (api.openai.com, Azure OpenAI
|
|
323
|
+
* deployments). Gates GA computer-use detection; identity supplies the model
|
|
324
|
+
* generation.
|
|
325
|
+
*/
|
|
326
|
+
function isDirectOpenAIResponsesEndpoint(spec) {
|
|
327
|
+
if (spec.api === "openai-responses") {
|
|
328
|
+
if (spec.provider !== "openai") return false;
|
|
329
|
+
if (!spec.baseUrl) return true;
|
|
330
|
+
try {
|
|
331
|
+
const url = new URL(spec.baseUrl);
|
|
332
|
+
return url.protocol === "https:" && url.hostname === "api.openai.com";
|
|
333
|
+
} catch {
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (spec.api !== "azure-openai-responses" || spec.provider !== "azure" && spec.provider !== "azure-openai") return false;
|
|
338
|
+
if (!spec.baseUrl) return true;
|
|
339
|
+
try {
|
|
340
|
+
const url = new URL(spec.baseUrl);
|
|
341
|
+
return url.protocol === "https:" && (url.hostname.endsWith(".openai.azure.com") || url.hostname === "models.inference.ai.azure.com");
|
|
342
|
+
} catch {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function explicitComputerUseConfig(spec) {
|
|
347
|
+
if (!("supportsComputerUseConfig" in spec)) return spec.supportsComputerUse;
|
|
348
|
+
const value = Reflect.get(spec, "supportsComputerUseConfig");
|
|
349
|
+
return typeof value === "boolean" ? value : void 0;
|
|
350
|
+
}
|
|
351
|
+
function revisionAtLeast(identity, major, minor) {
|
|
352
|
+
if (identity.revision === void 0) return false;
|
|
353
|
+
const [revMajor = 0, revMinor = 0] = identity.revision.split(".").map(Number);
|
|
354
|
+
return revMajor > major || revMajor === major && revMinor >= minor;
|
|
355
|
+
}
|
|
356
|
+
function supportsOpenAIGAComputerUse(spec, identity, explicitSupport) {
|
|
357
|
+
if (explicitSupport !== void 0) return explicitSupport;
|
|
358
|
+
if (!isDirectOpenAIResponsesEndpoint(spec)) return false;
|
|
359
|
+
const wireIdentity = spec.requestModelId === void 0 ? identity : resolveModelPolicy({
|
|
360
|
+
...spec,
|
|
361
|
+
id: spec.requestModelId
|
|
362
|
+
}).identity;
|
|
363
|
+
return wireIdentity.class === "openai" && revisionAtLeast(wireIdentity, 5, 4);
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Build one model from an authored spec. Bundled models.json rows are fully
|
|
367
|
+
* materialized by the generator and consumed directly (see `models.ts`), so
|
|
368
|
+
* this only runs for discovered/custom/override specs.
|
|
369
|
+
*/
|
|
370
|
+
function buildModel(spec) {
|
|
371
|
+
const policy = resolveModelPolicy(spec);
|
|
372
|
+
const supportsComputerUseConfig = explicitComputerUseConfig(spec);
|
|
373
|
+
const model = {
|
|
374
|
+
...spec,
|
|
375
|
+
reasoning: spec.reasoning || policy.thinking !== void 0,
|
|
376
|
+
name: cleanModelName(spec.name),
|
|
377
|
+
identity: policy.identity,
|
|
378
|
+
requiresGlyphTokenization: policy.identity.class === "anthropic",
|
|
379
|
+
tokenizer: spec.tokenizer ?? resolveModelTokenizer(spec.requestModelId ?? spec.id, spec.provider),
|
|
380
|
+
thinking: policy.thinking,
|
|
381
|
+
supportsComputerUse: supportsOpenAIGAComputerUse(spec, policy.identity, supportsComputerUseConfig),
|
|
382
|
+
supportsComputerUseConfig,
|
|
383
|
+
compat: policy.compat,
|
|
384
|
+
compatConfig: spec.compat
|
|
385
|
+
};
|
|
386
|
+
applyCatalogAssignments(model, policy.catalog);
|
|
387
|
+
applyCatalogCorrections(model, policy.catalog);
|
|
388
|
+
if (spec.kindConfig !== void 0) model.kind = spec.kindConfig;
|
|
389
|
+
if (spec.promptCacheConfig !== void 0) model.promptCache = { ...spec.promptCacheConfig };
|
|
390
|
+
return model;
|
|
391
|
+
}
|
|
392
|
+
//#endregion
|
|
393
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/discovery/protobuf.ts
|
|
394
|
+
const textEncoder = new TextEncoder();
|
|
395
|
+
const textDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
396
|
+
/** Creates a high-performance, lazy protobuf message codec from an IR field descriptor list. */
|
|
397
|
+
function pb(typeName, fields = []) {
|
|
398
|
+
let compiled;
|
|
399
|
+
function getCodec() {
|
|
400
|
+
if (!compiled) compiled = compileCodec(typeName, fields);
|
|
401
|
+
return compiled;
|
|
402
|
+
}
|
|
403
|
+
const codec = ((arg) => {
|
|
404
|
+
if (arg instanceof Uint8Array) return getCodec().decode(arg);
|
|
405
|
+
return getCodec().encode(arg);
|
|
406
|
+
});
|
|
407
|
+
codec.create = (value) => getCodec().create(value);
|
|
408
|
+
codec.encode = (value) => getCodec().encode(value);
|
|
409
|
+
codec.decode = (value) => getCodec().decode(value);
|
|
410
|
+
codec.toJson = (value) => getCodec().toJson(value);
|
|
411
|
+
return codec;
|
|
412
|
+
}
|
|
413
|
+
/** Creates a message using its codec's protobuf defaults. */
|
|
414
|
+
function create(codec, value) {
|
|
415
|
+
return codec.create(value);
|
|
416
|
+
}
|
|
417
|
+
/** Encodes a message using its codec. */
|
|
418
|
+
function toBinary(codec, value) {
|
|
419
|
+
return codec.encode(value);
|
|
420
|
+
}
|
|
421
|
+
/** Decodes wire bytes using a message codec. */
|
|
422
|
+
function fromBinary(codec, value) {
|
|
423
|
+
return codec.decode(value);
|
|
424
|
+
}
|
|
425
|
+
/** Encodes a JSON value as `google.protobuf.Value`. */
|
|
426
|
+
function encodeJsonValue(value) {
|
|
427
|
+
const writer = new Writer();
|
|
428
|
+
writeJsonValue(writer, value);
|
|
429
|
+
return writer.finish();
|
|
430
|
+
}
|
|
431
|
+
/** Decodes `google.protobuf.Value` wire bytes into a JSON value. */
|
|
432
|
+
function decodeJsonValue(value) {
|
|
433
|
+
return readJsonValue(new Reader(value));
|
|
434
|
+
}
|
|
435
|
+
function compileCodec(typeName, fieldDescs) {
|
|
436
|
+
const compiledFields = [];
|
|
437
|
+
const byNumber = /* @__PURE__ */ new Map();
|
|
438
|
+
for (const desc of fieldDescs) if (desc.kind === "oneof") {
|
|
439
|
+
const oneofHandler = compileOneofField(desc);
|
|
440
|
+
compiledFields.push(oneofHandler);
|
|
441
|
+
for (const v of desc.variants) byNumber.set(v.no, oneofHandler);
|
|
442
|
+
} else if (desc.kind === "map") {
|
|
443
|
+
const mapHandler = compileMapField(desc);
|
|
444
|
+
compiledFields.push(mapHandler);
|
|
445
|
+
byNumber.set(desc.no, mapHandler);
|
|
446
|
+
} else if (desc.kind === "message") {
|
|
447
|
+
const msgHandler = desc.repeat ? compileRepeatedField(desc.name, desc.no, messageValue(desc.T)) : compileSingularField(desc.name, desc.no, messageValue(desc.T));
|
|
448
|
+
compiledFields.push(msgHandler);
|
|
449
|
+
byNumber.set(desc.no, msgHandler);
|
|
450
|
+
} else {
|
|
451
|
+
const valCodec = scalarValue(desc.kind);
|
|
452
|
+
const scalarHandler = desc.repeat ? compileRepeatedField(desc.name, desc.no, valCodec) : compileSingularField(desc.name, desc.no, valCodec, desc.optional);
|
|
453
|
+
compiledFields.push(scalarHandler);
|
|
454
|
+
byNumber.set(desc.no, scalarHandler);
|
|
455
|
+
}
|
|
456
|
+
const codec = ((arg) => {
|
|
457
|
+
if (arg instanceof Uint8Array) return codec.decode(arg);
|
|
458
|
+
return codec.encode(arg);
|
|
459
|
+
});
|
|
460
|
+
codec.create = (value) => {
|
|
461
|
+
const message = typeName ? { $typeName: typeName } : {};
|
|
462
|
+
for (const f of compiledFields) f.initDefault(message);
|
|
463
|
+
if (value) for (const key in value) {
|
|
464
|
+
const v = Reflect.get(value, key);
|
|
465
|
+
if (v !== void 0) Reflect.set(message, key, v);
|
|
466
|
+
}
|
|
467
|
+
return message;
|
|
468
|
+
};
|
|
469
|
+
codec.encode = (value) => {
|
|
470
|
+
const writer = new Writer();
|
|
471
|
+
for (const f of compiledFields) f.encode(value, writer);
|
|
472
|
+
writeUnknownFields(value, writer);
|
|
473
|
+
return writer.finish();
|
|
474
|
+
};
|
|
475
|
+
codec.decode = (value) => {
|
|
476
|
+
const reader = new Reader(value);
|
|
477
|
+
const message = typeName ? { $typeName: typeName } : {};
|
|
478
|
+
for (const f of compiledFields) f.initDefault(message);
|
|
479
|
+
while (reader.pos < reader.len) {
|
|
480
|
+
const tag = reader.uint32();
|
|
481
|
+
const fieldNumber = tag >>> 3;
|
|
482
|
+
const wireType = tag & 7;
|
|
483
|
+
if (!isWireType(wireType)) throw new Error(`Unsupported protobuf wire type ${wireType} at byte ${reader.pos}`);
|
|
484
|
+
const field = byNumber.get(fieldNumber);
|
|
485
|
+
if (field) field.decode(message, reader, wireType, fieldNumber);
|
|
486
|
+
else {
|
|
487
|
+
const start = reader.pos;
|
|
488
|
+
reader.skip(wireType);
|
|
489
|
+
appendUnknownField(message, {
|
|
490
|
+
no: fieldNumber,
|
|
491
|
+
wireType,
|
|
492
|
+
data: reader.slice(start, reader.pos)
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return message;
|
|
497
|
+
};
|
|
498
|
+
codec.toJson = (value) => {
|
|
499
|
+
const output = {};
|
|
500
|
+
for (const f of compiledFields) f.toJson(value, output);
|
|
501
|
+
return output;
|
|
502
|
+
};
|
|
503
|
+
return codec;
|
|
504
|
+
}
|
|
505
|
+
function compileSingularField(name, number, value, optional = false) {
|
|
506
|
+
return {
|
|
507
|
+
number,
|
|
508
|
+
initDefault(message) {
|
|
509
|
+
if (!optional && value.defaultValue !== void 0) Reflect.set(message, name, value.defaultValue);
|
|
510
|
+
},
|
|
511
|
+
encode(message, writer) {
|
|
512
|
+
const input = Reflect.get(message, name);
|
|
513
|
+
if (input === void 0 || !optional && value.isDefault(input)) return;
|
|
514
|
+
writer.tag(number, value.wireType);
|
|
515
|
+
value.encode(input, writer);
|
|
516
|
+
},
|
|
517
|
+
decode(message, reader, wireType, _fieldNumber) {
|
|
518
|
+
assertWireType(wireType, value.wireType);
|
|
519
|
+
Reflect.set(message, name, value.decode(reader));
|
|
520
|
+
},
|
|
521
|
+
toJson(message, output) {
|
|
522
|
+
const input = Reflect.get(message, name);
|
|
523
|
+
if (input === void 0 || !optional && value.isDefault(input)) return;
|
|
524
|
+
output[name] = value.toJson(input);
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
function compileRepeatedField(name, number, value) {
|
|
529
|
+
return {
|
|
530
|
+
number,
|
|
531
|
+
initDefault(message) {
|
|
532
|
+
Reflect.set(message, name, []);
|
|
533
|
+
},
|
|
534
|
+
encode(message, writer) {
|
|
535
|
+
const items = Reflect.get(message, name);
|
|
536
|
+
if (!Array.isArray(items) || items.length === 0) return;
|
|
537
|
+
if (value.wireType !== 2 && isPackableScalar(value)) {
|
|
538
|
+
const packed = new Writer();
|
|
539
|
+
for (const item of items) value.encode(item, packed);
|
|
540
|
+
writer.tag(number, 2);
|
|
541
|
+
writer.lengthDelimited(packed.finish());
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
for (const item of items) {
|
|
545
|
+
writer.tag(number, value.wireType);
|
|
546
|
+
value.encode(item, writer);
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
decode(message, reader, wireType, _fieldNumber) {
|
|
550
|
+
const target = arrayField(message, name);
|
|
551
|
+
if (wireType === 2 && value.wireType !== 2 && isPackableScalar(value)) {
|
|
552
|
+
const limit = reader.uint32();
|
|
553
|
+
const end = reader.pos + limit;
|
|
554
|
+
while (reader.pos < end) target.push(value.decode(reader));
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
assertWireType(wireType, value.wireType);
|
|
558
|
+
target.push(value.decode(reader));
|
|
559
|
+
},
|
|
560
|
+
toJson(message, output) {
|
|
561
|
+
const items = Reflect.get(message, name);
|
|
562
|
+
if (!Array.isArray(items) || items.length === 0) return;
|
|
563
|
+
output[name] = items.map((item) => value.toJson(item));
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
function compileMapField(desc) {
|
|
568
|
+
const name = desc.name;
|
|
569
|
+
const number = desc.no;
|
|
570
|
+
const key = scalarValue("string");
|
|
571
|
+
const valCodec = typeof desc.V === "function" ? messageValue(desc.V) : scalarValue(desc.V);
|
|
572
|
+
return {
|
|
573
|
+
number,
|
|
574
|
+
initDefault(message) {
|
|
575
|
+
Reflect.set(message, name, Object.create(null));
|
|
576
|
+
},
|
|
577
|
+
encode(message, writer) {
|
|
578
|
+
const input = Reflect.get(message, name);
|
|
579
|
+
if (!isMessageObject(input)) return;
|
|
580
|
+
for (const entryKey in input) {
|
|
581
|
+
const entry = new Writer();
|
|
582
|
+
if (!key.isDefault(entryKey)) {
|
|
583
|
+
entry.tag(1, key.wireType);
|
|
584
|
+
key.encode(entryKey, entry);
|
|
585
|
+
}
|
|
586
|
+
const entryValue = input[entryKey];
|
|
587
|
+
if (!valCodec.isDefault(entryValue)) {
|
|
588
|
+
entry.tag(2, valCodec.wireType);
|
|
589
|
+
valCodec.encode(entryValue, entry);
|
|
590
|
+
}
|
|
591
|
+
writer.tag(number, 2);
|
|
592
|
+
writer.lengthDelimited(entry.finish());
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
decode(message, reader, wireType, _fieldNumber) {
|
|
596
|
+
assertWireType(wireType, 2);
|
|
597
|
+
const target = mapField(message, name);
|
|
598
|
+
const limit = reader.uint32();
|
|
599
|
+
const end = reader.pos + limit;
|
|
600
|
+
let entryKey = "";
|
|
601
|
+
let entryValue = valCodec.defaultValue;
|
|
602
|
+
while (reader.pos < end) {
|
|
603
|
+
const tag = reader.uint32();
|
|
604
|
+
const entryNumber = tag >>> 3;
|
|
605
|
+
const entryWireType = tag & 7;
|
|
606
|
+
if (!isWireType(entryWireType)) throw new Error(`Unsupported wire type ${entryWireType} in map entry`);
|
|
607
|
+
if (entryNumber === 1) {
|
|
608
|
+
assertWireType(entryWireType, key.wireType);
|
|
609
|
+
entryKey = requireString(key.decode(reader));
|
|
610
|
+
} else if (entryNumber === 2) {
|
|
611
|
+
assertWireType(entryWireType, valCodec.wireType);
|
|
612
|
+
entryValue = valCodec.decode(reader);
|
|
613
|
+
} else reader.skip(entryWireType);
|
|
614
|
+
}
|
|
615
|
+
target[entryKey] = entryValue;
|
|
616
|
+
},
|
|
617
|
+
toJson(message, output) {
|
|
618
|
+
const input = Reflect.get(message, name);
|
|
619
|
+
if (!isMessageObject(input)) return;
|
|
620
|
+
const mapOutput = Object.create(null);
|
|
621
|
+
for (const entryKey in input) mapOutput[entryKey] = valCodec.toJson(input[entryKey]);
|
|
622
|
+
output[name] = mapOutput;
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
function compileOneofField(desc) {
|
|
627
|
+
const name = desc.name;
|
|
628
|
+
const variantsByName = /* @__PURE__ */ new Map();
|
|
629
|
+
const variantsByNumber = /* @__PURE__ */ new Map();
|
|
630
|
+
for (const variant of desc.variants) {
|
|
631
|
+
const codec = variant.kind === "message" ? messageValue(variant.T) : scalarValue(variant.kind);
|
|
632
|
+
variantsByName.set(variant.name, {
|
|
633
|
+
no: variant.no,
|
|
634
|
+
codec
|
|
635
|
+
});
|
|
636
|
+
variantsByNumber.set(variant.no, {
|
|
637
|
+
name: variant.name,
|
|
638
|
+
codec
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
return {
|
|
642
|
+
number: 0,
|
|
643
|
+
initDefault(message) {
|
|
644
|
+
Reflect.set(message, name, { case: void 0 });
|
|
645
|
+
},
|
|
646
|
+
encode(message, writer) {
|
|
647
|
+
const oneof = Reflect.get(message, name);
|
|
648
|
+
if (!oneof || typeof oneof !== "object" || !("case" in oneof) || typeof oneof.case !== "string") return;
|
|
649
|
+
const variant = variantsByName.get(oneof.case);
|
|
650
|
+
if (!variant) return;
|
|
651
|
+
const value = Reflect.get(oneof, "value");
|
|
652
|
+
if (value === void 0) return;
|
|
653
|
+
writer.tag(variant.no, variant.codec.wireType);
|
|
654
|
+
variant.codec.encode(value, writer);
|
|
655
|
+
},
|
|
656
|
+
decode(message, reader, wireType, fieldNumber) {
|
|
657
|
+
const variant = variantsByNumber.get(fieldNumber);
|
|
658
|
+
if (!variant) throw new Error(`Unknown oneof field ${fieldNumber}`);
|
|
659
|
+
assertWireType(wireType, variant.codec.wireType);
|
|
660
|
+
Reflect.set(message, name, {
|
|
661
|
+
case: variant.name,
|
|
662
|
+
value: variant.codec.decode(reader)
|
|
663
|
+
});
|
|
664
|
+
},
|
|
665
|
+
toJson(message, output) {
|
|
666
|
+
const oneof = Reflect.get(message, name);
|
|
667
|
+
if (!oneof || typeof oneof !== "object" || !("case" in oneof) || typeof oneof.case !== "string") return;
|
|
668
|
+
const variant = variantsByName.get(oneof.case);
|
|
669
|
+
if (!variant) return;
|
|
670
|
+
const value = Reflect.get(oneof, "value");
|
|
671
|
+
if (value === void 0) return;
|
|
672
|
+
output[oneof.case] = variant.codec.toJson(value);
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
function isPackableScalar(value) {
|
|
677
|
+
return value.wireType === 0 || value.wireType === 1 || value.wireType === 5;
|
|
678
|
+
}
|
|
679
|
+
function scalarValue(kind) {
|
|
680
|
+
switch (kind) {
|
|
681
|
+
case "bool": return scalar(0, false, requireBoolean, (value, writer) => writer.bool(value), (reader) => reader.bool(), (value) => value);
|
|
682
|
+
case "bytes": return scalar(2, /* @__PURE__ */ new Uint8Array(0), requireBytes, (value, writer) => writer.bytes(value), (reader) => reader.bytes(), (value) => value.toBase64(), (value) => value.byteLength === 0);
|
|
683
|
+
case "double": return scalar(1, 0, requireNumber, (value, writer) => writer.double(value), (reader) => reader.double(), (value) => value);
|
|
684
|
+
case "enum": return scalar(0, 0, requireInt32, (value, writer) => writer.int32(value), (reader) => reader.int32(), (value) => value);
|
|
685
|
+
case "float": return scalar(5, 0, requireNumber, (value, writer) => writer.float(value), (reader) => reader.float(), (value) => value);
|
|
686
|
+
case "int32": return scalar(0, 0, requireInt32, (value, writer) => writer.int32(value), (reader) => reader.int32(), (value) => value);
|
|
687
|
+
case "int64": return scalar(0, 0n, requireBigInt, (value, writer) => writer.int64(value), (reader) => reader.int64(), (value) => value.toString());
|
|
688
|
+
case "string": return scalar(2, "", requireString, (value, writer) => writer.string(value), (reader) => reader.string(), (value) => value);
|
|
689
|
+
case "uint32": return scalar(0, 0, requireUint32, (value, writer) => writer.uint32(value), (reader) => reader.uint32(), (value) => value);
|
|
690
|
+
case "uint64": return scalar(0, 0n, requireUnsignedBigInt, (value, writer) => writer.uint64(value), (reader) => reader.uint64(), (value) => value.toString());
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
function scalar(wireType, defaultValue, validate, write, read, toJson, isDefault = (value) => value === defaultValue) {
|
|
694
|
+
return {
|
|
695
|
+
wireType,
|
|
696
|
+
defaultValue,
|
|
697
|
+
encode(value, writer) {
|
|
698
|
+
write(validate(value), writer);
|
|
699
|
+
},
|
|
700
|
+
decode(reader) {
|
|
701
|
+
return read(reader);
|
|
702
|
+
},
|
|
703
|
+
toJson(value) {
|
|
704
|
+
return toJson(validate(value));
|
|
705
|
+
},
|
|
706
|
+
isDefault(value) {
|
|
707
|
+
return isDefault(validate(value));
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
function messageValue(factory) {
|
|
712
|
+
let cached;
|
|
713
|
+
function getCodec() {
|
|
714
|
+
if (!cached) cached = factory();
|
|
715
|
+
return cached;
|
|
716
|
+
}
|
|
717
|
+
return {
|
|
718
|
+
wireType: 2,
|
|
719
|
+
defaultValue: void 0,
|
|
720
|
+
encode(value, writer) {
|
|
721
|
+
writer.lengthDelimited(getCodec().encode(value));
|
|
722
|
+
},
|
|
723
|
+
decode(reader) {
|
|
724
|
+
return getCodec().decode(reader.bytes());
|
|
725
|
+
},
|
|
726
|
+
toJson(value) {
|
|
727
|
+
return getCodec().toJson(value);
|
|
728
|
+
},
|
|
729
|
+
isDefault(value) {
|
|
730
|
+
return value === void 0;
|
|
731
|
+
}
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
function requireBoolean(value) {
|
|
735
|
+
if (typeof value === "boolean") return value;
|
|
736
|
+
throw new Error(`Expected boolean, got ${typeof value}`);
|
|
737
|
+
}
|
|
738
|
+
function requireBytes(value) {
|
|
739
|
+
if (value instanceof Uint8Array) return value;
|
|
740
|
+
throw new Error("Expected Uint8Array");
|
|
741
|
+
}
|
|
742
|
+
function requireNumber(value) {
|
|
743
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
744
|
+
throw new Error(`Expected number, got ${typeof value}`);
|
|
745
|
+
}
|
|
746
|
+
function requireInt32(value) {
|
|
747
|
+
if (typeof value === "number" && Number.isInteger(value)) return value | 0;
|
|
748
|
+
throw new Error(`Expected int32, got ${typeof value}`);
|
|
749
|
+
}
|
|
750
|
+
function requireString(value) {
|
|
751
|
+
if (typeof value === "string") return value;
|
|
752
|
+
throw new Error(`Expected string, got ${typeof value}`);
|
|
753
|
+
}
|
|
754
|
+
function requireBigInt(value) {
|
|
755
|
+
if (typeof value === "bigint") return value;
|
|
756
|
+
if (typeof value === "number" && Number.isInteger(value)) return BigInt(value);
|
|
757
|
+
if (typeof value === "string") return BigInt(value);
|
|
758
|
+
throw new Error(`Expected bigint, got ${typeof value}`);
|
|
759
|
+
}
|
|
760
|
+
function requireUint32(value) {
|
|
761
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 0) return value >>> 0;
|
|
762
|
+
throw new Error(`Expected uint32, got ${typeof value}`);
|
|
763
|
+
}
|
|
764
|
+
function requireUnsignedBigInt(value) {
|
|
765
|
+
const b = requireBigInt(value);
|
|
766
|
+
if (b < 0n) throw new Error("Expected unsigned bigint");
|
|
767
|
+
return b;
|
|
768
|
+
}
|
|
769
|
+
function arrayField(message, name) {
|
|
770
|
+
let arr = Reflect.get(message, name);
|
|
771
|
+
if (!Array.isArray(arr)) {
|
|
772
|
+
arr = [];
|
|
773
|
+
Reflect.set(message, name, arr);
|
|
774
|
+
}
|
|
775
|
+
return arr;
|
|
776
|
+
}
|
|
777
|
+
function mapField(message, name) {
|
|
778
|
+
const value = Reflect.get(message, name);
|
|
779
|
+
if (isRecord(value)) return value;
|
|
780
|
+
const map = Object.create(null);
|
|
781
|
+
Reflect.set(message, name, map);
|
|
782
|
+
return map;
|
|
783
|
+
}
|
|
784
|
+
function appendUnknownField(message, field) {
|
|
785
|
+
const existing = Reflect.get(message, "$unknown");
|
|
786
|
+
if (isUnknownFields(existing)) {
|
|
787
|
+
existing.push(field);
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
Reflect.set(message, "$unknown", [field]);
|
|
791
|
+
}
|
|
792
|
+
function isUnknownFields(value) {
|
|
793
|
+
return Array.isArray(value) && value.every(isUnknownField);
|
|
794
|
+
}
|
|
795
|
+
function writeUnknownFields(message, writer) {
|
|
796
|
+
const bag = Reflect.get(message, "$unknown");
|
|
797
|
+
if (!Array.isArray(bag)) return;
|
|
798
|
+
for (const field of bag) if (isUnknownField(field)) {
|
|
799
|
+
writer.tag(field.no, field.wireType);
|
|
800
|
+
writer.raw(field.data);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
function isUnknownField(value) {
|
|
804
|
+
return isRecord(value) && typeof value.no === "number" && typeof value.wireType === "number" && isWireType(value.wireType) && value.data instanceof Uint8Array;
|
|
805
|
+
}
|
|
806
|
+
function isMessageObject(value) {
|
|
807
|
+
return isRecord(value) && !(value instanceof Uint8Array);
|
|
808
|
+
}
|
|
809
|
+
function isWireType(value) {
|
|
810
|
+
return value === 0 || value === 1 || value === 2 || value === 5;
|
|
811
|
+
}
|
|
812
|
+
function assertWireType(actual, expected) {
|
|
813
|
+
if (actual !== expected) throw new Error(`Unexpected protobuf wire type ${actual}; expected ${expected}`);
|
|
814
|
+
}
|
|
815
|
+
function isArrayBufferBacked(bytes) {
|
|
816
|
+
return bytes?.buffer instanceof ArrayBuffer;
|
|
817
|
+
}
|
|
818
|
+
var Writer = class {
|
|
819
|
+
#chunks = [];
|
|
820
|
+
#length = 0;
|
|
821
|
+
tag(number, wireType) {
|
|
822
|
+
this.uint32(number << 3 | wireType);
|
|
823
|
+
}
|
|
824
|
+
uint32(value) {
|
|
825
|
+
let v = value >>> 0;
|
|
826
|
+
const buffer = /* @__PURE__ */ new Uint8Array(5);
|
|
827
|
+
let pos = 0;
|
|
828
|
+
while (v > 127) {
|
|
829
|
+
buffer[pos++] = v & 127 | 128;
|
|
830
|
+
v >>>= 7;
|
|
831
|
+
}
|
|
832
|
+
buffer[pos++] = v;
|
|
833
|
+
this.raw(buffer.subarray(0, pos));
|
|
834
|
+
}
|
|
835
|
+
int32(value) {
|
|
836
|
+
if (value >= 0) {
|
|
837
|
+
this.uint32(value);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
this.int64(BigInt(value));
|
|
841
|
+
}
|
|
842
|
+
int64(value) {
|
|
843
|
+
let v = BigInt.asUintN(64, value);
|
|
844
|
+
const buffer = /* @__PURE__ */ new Uint8Array(10);
|
|
845
|
+
let pos = 0;
|
|
846
|
+
while (v > 127n) {
|
|
847
|
+
buffer[pos++] = Number(v & 127n) | 128;
|
|
848
|
+
v >>= 7n;
|
|
849
|
+
}
|
|
850
|
+
buffer[pos++] = Number(v);
|
|
851
|
+
this.raw(buffer.subarray(0, pos));
|
|
852
|
+
}
|
|
853
|
+
uint64(value) {
|
|
854
|
+
this.int64(value);
|
|
855
|
+
}
|
|
856
|
+
bool(value) {
|
|
857
|
+
this.raw(new Uint8Array([value ? 1 : 0]));
|
|
858
|
+
}
|
|
859
|
+
float(value) {
|
|
860
|
+
const buffer = /* @__PURE__ */ new Uint8Array(4);
|
|
861
|
+
new DataView(buffer.buffer).setFloat32(0, value, true);
|
|
862
|
+
this.raw(buffer);
|
|
863
|
+
}
|
|
864
|
+
double(value) {
|
|
865
|
+
const buffer = /* @__PURE__ */ new Uint8Array(8);
|
|
866
|
+
new DataView(buffer.buffer).setFloat64(0, value, true);
|
|
867
|
+
this.raw(buffer);
|
|
868
|
+
}
|
|
869
|
+
string(value) {
|
|
870
|
+
this.lengthDelimited(textEncoder.encode(value));
|
|
871
|
+
}
|
|
872
|
+
bytes(value) {
|
|
873
|
+
this.lengthDelimited(value);
|
|
874
|
+
}
|
|
875
|
+
lengthDelimited(value) {
|
|
876
|
+
this.uint32(value.byteLength);
|
|
877
|
+
this.raw(value);
|
|
878
|
+
}
|
|
879
|
+
raw(chunk) {
|
|
880
|
+
this.#chunks.push(chunk);
|
|
881
|
+
this.#length += chunk.byteLength;
|
|
882
|
+
}
|
|
883
|
+
/** Wire bytes on a plain `ArrayBuffer`, so they satisfy `fetch`'s `BodyInit` as-is. */
|
|
884
|
+
finish() {
|
|
885
|
+
const [only] = this.#chunks;
|
|
886
|
+
if (this.#chunks.length === 1 && isArrayBufferBacked(only)) return only;
|
|
887
|
+
const result = new Uint8Array(this.#length);
|
|
888
|
+
let offset = 0;
|
|
889
|
+
for (const chunk of this.#chunks) {
|
|
890
|
+
result.set(chunk, offset);
|
|
891
|
+
offset += chunk.byteLength;
|
|
892
|
+
}
|
|
893
|
+
return result;
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
var Reader = class {
|
|
897
|
+
buf;
|
|
898
|
+
len;
|
|
899
|
+
pos = 0;
|
|
900
|
+
constructor(buf) {
|
|
901
|
+
this.buf = buf;
|
|
902
|
+
this.len = buf.byteLength;
|
|
903
|
+
}
|
|
904
|
+
uint32() {
|
|
905
|
+
let result = 0;
|
|
906
|
+
let shift = 0;
|
|
907
|
+
while (this.pos < this.len) {
|
|
908
|
+
const byte = this.buf[this.pos++];
|
|
909
|
+
result |= (byte & 127) << shift;
|
|
910
|
+
if ((byte & 128) === 0) return result >>> 0;
|
|
911
|
+
shift += 7;
|
|
912
|
+
if (shift >= 32) throw new Error("Varint exceeds 32 bits");
|
|
913
|
+
}
|
|
914
|
+
throw new Error("Unexpected end of protobuf varint");
|
|
915
|
+
}
|
|
916
|
+
int32() {
|
|
917
|
+
return Number(BigInt.asIntN(32, this.uint64()));
|
|
918
|
+
}
|
|
919
|
+
int64() {
|
|
920
|
+
let result = 0n;
|
|
921
|
+
let shift = 0n;
|
|
922
|
+
while (this.pos < this.len) {
|
|
923
|
+
const byte = this.buf[this.pos++];
|
|
924
|
+
result |= BigInt(byte & 127) << shift;
|
|
925
|
+
if ((byte & 128) === 0) return BigInt.asIntN(64, result);
|
|
926
|
+
shift += 7n;
|
|
927
|
+
if (shift >= 64n) throw new Error("Varint exceeds 64 bits");
|
|
928
|
+
}
|
|
929
|
+
throw new Error("Unexpected end of protobuf 64-bit varint");
|
|
930
|
+
}
|
|
931
|
+
uint64() {
|
|
932
|
+
return BigInt.asUintN(64, this.int64());
|
|
933
|
+
}
|
|
934
|
+
bool() {
|
|
935
|
+
return this.uint32() !== 0;
|
|
936
|
+
}
|
|
937
|
+
float() {
|
|
938
|
+
if (this.pos + 4 > this.len) throw new Error("Unexpected EOF reading float");
|
|
939
|
+
const view = new DataView(this.buf.buffer, this.buf.byteOffset + this.pos, 4);
|
|
940
|
+
this.pos += 4;
|
|
941
|
+
return view.getFloat32(0, true);
|
|
942
|
+
}
|
|
943
|
+
double() {
|
|
944
|
+
if (this.pos + 8 > this.len) throw new Error("Unexpected EOF reading double");
|
|
945
|
+
const view = new DataView(this.buf.buffer, this.buf.byteOffset + this.pos, 8);
|
|
946
|
+
this.pos += 8;
|
|
947
|
+
return view.getFloat64(0, true);
|
|
948
|
+
}
|
|
949
|
+
string() {
|
|
950
|
+
return textDecoder.decode(this.bytes());
|
|
951
|
+
}
|
|
952
|
+
bytes() {
|
|
953
|
+
const length = this.uint32();
|
|
954
|
+
if (this.pos + length > this.len) throw new Error("Unexpected EOF reading bytes");
|
|
955
|
+
const result = this.buf.subarray(this.pos, this.pos + length);
|
|
956
|
+
this.pos += length;
|
|
957
|
+
return result;
|
|
958
|
+
}
|
|
959
|
+
slice(start, end) {
|
|
960
|
+
return this.buf.subarray(start, end);
|
|
961
|
+
}
|
|
962
|
+
skip(wireType) {
|
|
963
|
+
switch (wireType) {
|
|
964
|
+
case 0:
|
|
965
|
+
this.int64();
|
|
966
|
+
return;
|
|
967
|
+
case 1:
|
|
968
|
+
if (this.pos + 8 > this.len) throw new Error("Unexpected EOF skipping 64-bit");
|
|
969
|
+
this.pos += 8;
|
|
970
|
+
return;
|
|
971
|
+
case 2:
|
|
972
|
+
this.bytes();
|
|
973
|
+
return;
|
|
974
|
+
case 5:
|
|
975
|
+
if (this.pos + 4 > this.len) throw new Error("Unexpected EOF skipping 32-bit");
|
|
976
|
+
this.pos += 4;
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
function writeJsonValue(writer, value) {
|
|
982
|
+
if (value === null) {
|
|
983
|
+
writer.tag(1, 0);
|
|
984
|
+
writer.uint32(0);
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (typeof value === "number") {
|
|
988
|
+
writer.tag(2, 1);
|
|
989
|
+
writer.double(value);
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
if (typeof value === "string") {
|
|
993
|
+
writer.tag(3, 2);
|
|
994
|
+
writer.string(value);
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
if (typeof value === "boolean") {
|
|
998
|
+
writer.tag(4, 0);
|
|
999
|
+
writer.bool(value);
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
if (Array.isArray(value)) {
|
|
1003
|
+
const listWriter = new Writer();
|
|
1004
|
+
for (const item of value) {
|
|
1005
|
+
listWriter.tag(1, 2);
|
|
1006
|
+
const itemWriter = new Writer();
|
|
1007
|
+
writeJsonValue(itemWriter, item);
|
|
1008
|
+
listWriter.lengthDelimited(itemWriter.finish());
|
|
1009
|
+
}
|
|
1010
|
+
writer.tag(6, 2);
|
|
1011
|
+
writer.lengthDelimited(listWriter.finish());
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
if (isRecord(value)) {
|
|
1015
|
+
const structWriter = new Writer();
|
|
1016
|
+
for (const key in value) {
|
|
1017
|
+
const item = value[key];
|
|
1018
|
+
const entryWriter = new Writer();
|
|
1019
|
+
entryWriter.tag(1, 2);
|
|
1020
|
+
entryWriter.string(key);
|
|
1021
|
+
entryWriter.tag(2, 2);
|
|
1022
|
+
const valueWriter = new Writer();
|
|
1023
|
+
writeJsonValue(valueWriter, item);
|
|
1024
|
+
entryWriter.lengthDelimited(valueWriter.finish());
|
|
1025
|
+
structWriter.tag(1, 2);
|
|
1026
|
+
structWriter.lengthDelimited(entryWriter.finish());
|
|
1027
|
+
}
|
|
1028
|
+
writer.tag(5, 2);
|
|
1029
|
+
writer.lengthDelimited(structWriter.finish());
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
function readJsonValue(reader) {
|
|
1033
|
+
let value = null;
|
|
1034
|
+
while (reader.pos < reader.len) {
|
|
1035
|
+
const tag = reader.uint32();
|
|
1036
|
+
const fieldNumber = tag >>> 3;
|
|
1037
|
+
const wireType = tag & 7;
|
|
1038
|
+
if (!isWireType(wireType)) throw new Error(`Unsupported wire type ${wireType} in google.protobuf.Value`);
|
|
1039
|
+
switch (fieldNumber) {
|
|
1040
|
+
case 1:
|
|
1041
|
+
assertWireType(wireType, 0);
|
|
1042
|
+
reader.uint32();
|
|
1043
|
+
value = null;
|
|
1044
|
+
break;
|
|
1045
|
+
case 2:
|
|
1046
|
+
assertWireType(wireType, 1);
|
|
1047
|
+
value = reader.double();
|
|
1048
|
+
break;
|
|
1049
|
+
case 3:
|
|
1050
|
+
assertWireType(wireType, 2);
|
|
1051
|
+
value = reader.string();
|
|
1052
|
+
break;
|
|
1053
|
+
case 4:
|
|
1054
|
+
assertWireType(wireType, 0);
|
|
1055
|
+
value = reader.bool();
|
|
1056
|
+
break;
|
|
1057
|
+
case 5:
|
|
1058
|
+
assertWireType(wireType, 2);
|
|
1059
|
+
value = readJsonStruct(new Reader(reader.bytes()));
|
|
1060
|
+
break;
|
|
1061
|
+
case 6:
|
|
1062
|
+
assertWireType(wireType, 2);
|
|
1063
|
+
value = readJsonList(new Reader(reader.bytes()));
|
|
1064
|
+
break;
|
|
1065
|
+
default: reader.skip(wireType);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
return value;
|
|
1069
|
+
}
|
|
1070
|
+
function readJsonStruct(reader) {
|
|
1071
|
+
const output = {};
|
|
1072
|
+
while (reader.pos < reader.len) {
|
|
1073
|
+
const tag = reader.uint32();
|
|
1074
|
+
const fieldNumber = tag >>> 3;
|
|
1075
|
+
const wireType = tag & 7;
|
|
1076
|
+
if (!isWireType(wireType)) throw new Error(`Unsupported wire type ${wireType} in Struct`);
|
|
1077
|
+
if (fieldNumber === 1) {
|
|
1078
|
+
assertWireType(wireType, 2);
|
|
1079
|
+
const entryReader = new Reader(reader.bytes());
|
|
1080
|
+
let entryKey = "";
|
|
1081
|
+
let entryVal = null;
|
|
1082
|
+
while (entryReader.pos < entryReader.len) {
|
|
1083
|
+
const entryTag = entryReader.uint32();
|
|
1084
|
+
const entryNo = entryTag >>> 3;
|
|
1085
|
+
const entryWire = entryTag & 7;
|
|
1086
|
+
if (entryNo === 1) entryKey = entryReader.string();
|
|
1087
|
+
else if (entryNo === 2) entryVal = readJsonValue(new Reader(entryReader.bytes()));
|
|
1088
|
+
else if (isWireType(entryWire)) entryReader.skip(entryWire);
|
|
1089
|
+
}
|
|
1090
|
+
output[entryKey] = entryVal;
|
|
1091
|
+
} else reader.skip(wireType);
|
|
1092
|
+
}
|
|
1093
|
+
return output;
|
|
1094
|
+
}
|
|
1095
|
+
function readJsonList(reader) {
|
|
1096
|
+
const list = [];
|
|
1097
|
+
while (reader.pos < reader.len) {
|
|
1098
|
+
const tag = reader.uint32();
|
|
1099
|
+
const fieldNumber = tag >>> 3;
|
|
1100
|
+
const wireType = tag & 7;
|
|
1101
|
+
if (!isWireType(wireType)) throw new Error(`Unsupported wire type ${wireType} in ListValue`);
|
|
1102
|
+
if (fieldNumber === 1) {
|
|
1103
|
+
assertWireType(wireType, 2);
|
|
1104
|
+
list.push(readJsonValue(new Reader(reader.bytes())));
|
|
1105
|
+
} else reader.skip(wireType);
|
|
1106
|
+
}
|
|
1107
|
+
return list;
|
|
1108
|
+
}
|
|
1109
|
+
//#endregion
|
|
1110
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/compat/types.ts
|
|
1111
|
+
/**
|
|
1112
|
+
* Revision placeholder in a templated `variant-family` (`gemini-{rev}-flash`).
|
|
1113
|
+
* A family whose id carries it is instantiated once per live revision that
|
|
1114
|
+
* discovery advertises, so new generations of a lineage collapse without a
|
|
1115
|
+
* new reviewed entry.
|
|
1116
|
+
*/
|
|
1117
|
+
const REVISION_PLACEHOLDER = "{rev}";
|
|
1118
|
+
//#endregion
|
|
1119
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/compat/collapse.ts
|
|
1120
|
+
const VARIANT_ROUTING_KEYS = ["off", ...THINKING_EFFORTS];
|
|
1121
|
+
const DEFAULT_PAIR_EFFORTS = [
|
|
1122
|
+
"minimal",
|
|
1123
|
+
"low",
|
|
1124
|
+
"medium",
|
|
1125
|
+
"high"
|
|
1126
|
+
];
|
|
1127
|
+
/**
|
|
1128
|
+
* Build one effort-tier family from a tier→wire-id map: routing keeps only the
|
|
1129
|
+
* listed efforts, `members` dedupes the targets in tier order, and thinking is
|
|
1130
|
+
* `mode: "effort"` (mandatory when the family has no `off` route). Shared by the
|
|
1131
|
+
* Devin and Cursor tables, whose per-effort siblings follow the same shape.
|
|
1132
|
+
*/
|
|
1133
|
+
function tierFamily(id, name, routes, efforts, defaultMember) {
|
|
1134
|
+
const routing = {};
|
|
1135
|
+
if (routes.off) routing.off = routes.off;
|
|
1136
|
+
for (const effort of efforts) switch (effort) {
|
|
1137
|
+
case "minimal":
|
|
1138
|
+
if (routes.minimal) routing[effort] = routes.minimal;
|
|
1139
|
+
break;
|
|
1140
|
+
case "low":
|
|
1141
|
+
if (routes.low) routing[effort] = routes.low;
|
|
1142
|
+
break;
|
|
1143
|
+
case "medium":
|
|
1144
|
+
if (routes.medium) routing[effort] = routes.medium;
|
|
1145
|
+
break;
|
|
1146
|
+
case "high":
|
|
1147
|
+
if (routes.high) routing[effort] = routes.high;
|
|
1148
|
+
break;
|
|
1149
|
+
case "xhigh":
|
|
1150
|
+
if (routes.xhigh) routing[effort] = routes.xhigh;
|
|
1151
|
+
break;
|
|
1152
|
+
case "max": if (routes.max) routing[effort] = routes.max;
|
|
1153
|
+
}
|
|
1154
|
+
return {
|
|
1155
|
+
id,
|
|
1156
|
+
name,
|
|
1157
|
+
members: [
|
|
1158
|
+
routes.off,
|
|
1159
|
+
routes.minimal,
|
|
1160
|
+
routes.low,
|
|
1161
|
+
routes.medium,
|
|
1162
|
+
routes.high,
|
|
1163
|
+
routes.xhigh,
|
|
1164
|
+
routes.max
|
|
1165
|
+
].filter((member, index, items) => typeof member === "string" && items.indexOf(member) === index),
|
|
1166
|
+
routing,
|
|
1167
|
+
thinking: {
|
|
1168
|
+
mode: "effort",
|
|
1169
|
+
efforts,
|
|
1170
|
+
...routes.off ? void 0 : { requiresEffort: true }
|
|
1171
|
+
},
|
|
1172
|
+
...defaultMember !== void 0 ? { defaultMember } : void 0
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
/** One reviewed family from the compiled collapse vocabulary → runtime shape. */
|
|
1176
|
+
function compiledFamily(compiled) {
|
|
1177
|
+
const family = {
|
|
1178
|
+
id: compiled.id,
|
|
1179
|
+
name: compiled.name,
|
|
1180
|
+
members: compiled.members,
|
|
1181
|
+
routing: compiled.routing
|
|
1182
|
+
};
|
|
1183
|
+
if (compiled.defaultMember !== void 0) family.defaultMember = compiled.defaultMember;
|
|
1184
|
+
if (compiled.retiredMembers?.length) family.retiredMembers = compiled.retiredMembers;
|
|
1185
|
+
if (!compiled.noThinking && compiled.mode !== void 0) family.thinking = {
|
|
1186
|
+
mode: compiled.mode,
|
|
1187
|
+
efforts: compiled.efforts ?? [],
|
|
1188
|
+
...compiled.effortBudgets !== void 0 && { effortBudgets: compiled.effortBudgets },
|
|
1189
|
+
...compiled.defaultLevel !== void 0 && { defaultLevel: compiled.defaultLevel },
|
|
1190
|
+
...compiled.requiresEffort === true && { requiresEffort: true }
|
|
1191
|
+
};
|
|
1192
|
+
if (compiled.suppressWhenOff) family.suppressWhenOff = true;
|
|
1193
|
+
if (compiled.preserveAbsentEffortRoutes) family.preserveAbsentEffortRoutes = true;
|
|
1194
|
+
if (compiled.extraAliases?.length) family.extraAliases = compiled.extraAliases;
|
|
1195
|
+
return family;
|
|
1196
|
+
}
|
|
1197
|
+
const REVISION_CAPTURE = String.raw`(\d+(?:\.\d+){0,2})`;
|
|
1198
|
+
/** One compiled `{rev}` family → runtime template with its id matcher. */
|
|
1199
|
+
function compiledTemplate(compiled) {
|
|
1200
|
+
const family = compiledFamily(compiled);
|
|
1201
|
+
const alternatives = [
|
|
1202
|
+
family.id,
|
|
1203
|
+
...family.members,
|
|
1204
|
+
...family.extraAliases ?? []
|
|
1205
|
+
].map((id) => id.split(REVISION_PLACEHOLDER).map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join(REVISION_CAPTURE));
|
|
1206
|
+
const template = {
|
|
1207
|
+
family,
|
|
1208
|
+
pattern: new RegExp(`^(?:${alternatives.join("|")})$`, "i")
|
|
1209
|
+
};
|
|
1210
|
+
if (compiled.revision !== void 0) {
|
|
1211
|
+
const terms = parseRevisionConstraint(compiled.revision);
|
|
1212
|
+
if (terms !== void 0) template.revision = terms;
|
|
1213
|
+
}
|
|
1214
|
+
return template;
|
|
1215
|
+
}
|
|
1216
|
+
/** Substitute the placeholder throughout one templated family. */
|
|
1217
|
+
function instantiateTemplate(template, rev) {
|
|
1218
|
+
if (template.revision !== void 0) {
|
|
1219
|
+
const parsed = parseRevision(rev);
|
|
1220
|
+
if (parsed === void 0 || !revisionSatisfies(parsed, template.revision)) return void 0;
|
|
1221
|
+
}
|
|
1222
|
+
const fill = (id) => id.replaceAll(REVISION_PLACEHOLDER, rev);
|
|
1223
|
+
const source = template.family;
|
|
1224
|
+
const routing = {};
|
|
1225
|
+
for (const effort of VARIANT_ROUTING_KEYS) {
|
|
1226
|
+
const target = source.routing[effort];
|
|
1227
|
+
if (target !== void 0) routing[effort] = fill(target);
|
|
1228
|
+
}
|
|
1229
|
+
const family = {
|
|
1230
|
+
...source,
|
|
1231
|
+
id: fill(source.id),
|
|
1232
|
+
name: fill(source.name),
|
|
1233
|
+
members: source.members.map(fill),
|
|
1234
|
+
routing
|
|
1235
|
+
};
|
|
1236
|
+
if (source.defaultMember !== void 0) family.defaultMember = fill(source.defaultMember);
|
|
1237
|
+
if (source.retiredMembers !== void 0) family.retiredMembers = source.retiredMembers.map(fill);
|
|
1238
|
+
if (source.extraAliases !== void 0) family.extraAliases = source.extraAliases.map(fill);
|
|
1239
|
+
return family;
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* The family a template yields for `id` (logical id, member, or alias), or
|
|
1243
|
+
* undefined when no template matches or the revision is out of range.
|
|
1244
|
+
*/
|
|
1245
|
+
function templateFamilyFor(templates, id) {
|
|
1246
|
+
for (const template of templates) {
|
|
1247
|
+
const match = template.pattern.exec(id);
|
|
1248
|
+
if (match === null) continue;
|
|
1249
|
+
let rev;
|
|
1250
|
+
for (let group = 1; group < match.length && rev === void 0; group++) rev = match[group];
|
|
1251
|
+
if (rev === void 0) continue;
|
|
1252
|
+
const family = instantiateTemplate(template, rev);
|
|
1253
|
+
if (family !== void 0) return family;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Concrete families for every revision present in `ids`, one per
|
|
1258
|
+
* instantiated id, skipping ids a concrete family in `table` already owns.
|
|
1259
|
+
*/
|
|
1260
|
+
function instantiateTemplates(table, ids) {
|
|
1261
|
+
const templates = table.templates;
|
|
1262
|
+
if (templates === void 0 || templates.length === 0) return [];
|
|
1263
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1264
|
+
for (const family of table.families) seen.add(family.id);
|
|
1265
|
+
const out = [];
|
|
1266
|
+
for (const id of ids) {
|
|
1267
|
+
const family = templateFamilyFor(templates, id);
|
|
1268
|
+
if (family === void 0 || seen.has(family.id)) continue;
|
|
1269
|
+
seen.add(family.id);
|
|
1270
|
+
out.push(family);
|
|
1271
|
+
}
|
|
1272
|
+
return out;
|
|
1273
|
+
}
|
|
1274
|
+
/** Provider id → reviewed collapse table, built once from the compiled vocabulary. */
|
|
1275
|
+
function buildCompiledTables() {
|
|
1276
|
+
const { variantFamilies, providerAliases } = collapseVocabulary();
|
|
1277
|
+
const tables = {};
|
|
1278
|
+
for (const compiled of variantFamilies) {
|
|
1279
|
+
const table = tables[compiled.provider] ??= { families: [] };
|
|
1280
|
+
if (compiled.id.includes("{rev}")) (table.templates ??= []).push(compiledTemplate(compiled));
|
|
1281
|
+
else table.families.push(compiledFamily(compiled));
|
|
1282
|
+
}
|
|
1283
|
+
for (const [provider, aliases] of Object.entries(providerAliases)) {
|
|
1284
|
+
tables[provider] ??= { families: [] };
|
|
1285
|
+
tables[provider].providerAliases = aliases;
|
|
1286
|
+
}
|
|
1287
|
+
return tables;
|
|
1288
|
+
}
|
|
1289
|
+
const CURSOR_TIER_ID_PATTERN = /^(.+?)-(extra-high|none|minimal|low|medium|high|xhigh|max)(-fast)?$/;
|
|
1290
|
+
const CURSOR_TIER_BASE_PATTERN = /-(extra-high|none|minimal|low|medium|high|xhigh|max)$/;
|
|
1291
|
+
const CURSOR_THINKING_TOKEN_PATTERN = /(^|-)thinking($|-)/;
|
|
1292
|
+
const CURSOR_TIER_BY_TOKEN = {
|
|
1293
|
+
none: "none",
|
|
1294
|
+
minimal: "minimal",
|
|
1295
|
+
low: "low",
|
|
1296
|
+
medium: "medium",
|
|
1297
|
+
high: "high",
|
|
1298
|
+
"extra-high": "xhigh",
|
|
1299
|
+
xhigh: "xhigh",
|
|
1300
|
+
max: "max"
|
|
1301
|
+
};
|
|
1302
|
+
/** Whether an existing logical row already routes every live member in `members`. */
|
|
1303
|
+
function collapsedCursorLogicalMatches(spec, members) {
|
|
1304
|
+
const routing = spec.thinking?.effortRouting;
|
|
1305
|
+
if (!routing) return false;
|
|
1306
|
+
for (const member of members) {
|
|
1307
|
+
if (spec.requestModelId === member.spec.id) continue;
|
|
1308
|
+
let matched = false;
|
|
1309
|
+
for (const effort of VARIANT_ROUTING_KEYS) if (routing[effort] === member.spec.id) {
|
|
1310
|
+
matched = true;
|
|
1311
|
+
break;
|
|
1312
|
+
}
|
|
1313
|
+
if (!matched) return false;
|
|
1314
|
+
}
|
|
1315
|
+
return true;
|
|
1316
|
+
}
|
|
1317
|
+
/**
|
|
1318
|
+
* Derive safe Cursor per-effort families from live wire ids. A family is
|
|
1319
|
+
* intentionally left expanded when its base is an independent live SKU, any
|
|
1320
|
+
* member already has a thinking ladder, member metadata differs, or a tier
|
|
1321
|
+
* token is also part of a product name.
|
|
1322
|
+
*/
|
|
1323
|
+
function deriveCursorEffortFamilies(specs) {
|
|
1324
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1325
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1326
|
+
const candidateBases = /* @__PURE__ */ new Set();
|
|
1327
|
+
for (const spec of specs) {
|
|
1328
|
+
if (!byId.has(spec.id)) byId.set(spec.id, spec);
|
|
1329
|
+
const match = CURSOR_TIER_ID_PATTERN.exec(spec.id);
|
|
1330
|
+
if (!match) continue;
|
|
1331
|
+
const baseId = match[1];
|
|
1332
|
+
const tier = CURSOR_TIER_BY_TOKEN[match[2] ?? ""];
|
|
1333
|
+
const fast = match[3] !== void 0;
|
|
1334
|
+
if (!baseId || !tier) continue;
|
|
1335
|
+
const member = {
|
|
1336
|
+
baseId,
|
|
1337
|
+
fast,
|
|
1338
|
+
spec,
|
|
1339
|
+
tier
|
|
1340
|
+
};
|
|
1341
|
+
const key = `${baseId}\0${fast ? "fast" : "standard"}`;
|
|
1342
|
+
const group = groups.get(key);
|
|
1343
|
+
if (group) group.push(member);
|
|
1344
|
+
else groups.set(key, [member]);
|
|
1345
|
+
candidateBases.add(baseId);
|
|
1346
|
+
}
|
|
1347
|
+
const unsafeBases = /* @__PURE__ */ new Set();
|
|
1348
|
+
for (const group of groups.values()) {
|
|
1349
|
+
const first = group[0];
|
|
1350
|
+
if (!first) continue;
|
|
1351
|
+
const { baseId } = first;
|
|
1352
|
+
const standardGroup = groups.get(`${baseId}\0standard`) ?? [];
|
|
1353
|
+
const standardBase = byId.get(baseId);
|
|
1354
|
+
const laneBase = byId.get(`${baseId}${first.fast ? "-fast" : ""}`);
|
|
1355
|
+
const independentStandardBase = standardBase !== void 0 && !collapsedCursorLogicalMatches(standardBase, standardGroup);
|
|
1356
|
+
const independentLaneBase = laneBase !== void 0 && !collapsedCursorLogicalMatches(laneBase, group);
|
|
1357
|
+
if (independentStandardBase || independentLaneBase || new Set(group.map((member) => member.tier)).size !== group.length || CURSOR_TIER_BASE_PATTERN.test(baseId) || CURSOR_THINKING_TOKEN_PATTERN.test(baseId) || candidateBases.has(`${baseId}-thinking`) || byId.has(`${baseId}-thinking`) || byId.has(`${baseId}-thinking-fast`) || byId.has(`${baseId}-fast-thinking`) || group.some((member) => member.spec.thinking !== void 0 || member.spec.requestModelId !== void 0) || group.some((member) => candidateBases.has(`${baseId}-${member.tier}`))) unsafeBases.add(baseId);
|
|
1358
|
+
}
|
|
1359
|
+
const families = [];
|
|
1360
|
+
for (const group of groups.values()) {
|
|
1361
|
+
const first = group[0];
|
|
1362
|
+
if (!first || group.length < 2 || unsafeBases.has(first.baseId)) continue;
|
|
1363
|
+
if (group.some((member) => member.spec.api !== first.spec.api || member.spec.baseUrl !== first.spec.baseUrl || member.spec.contextWindow !== first.spec.contextWindow || member.spec.maxTokens !== first.spec.maxTokens || member.spec.cursorMaxMode !== first.spec.cursorMaxMode || !Bun.deepEquals(member.spec.cost, first.spec.cost) || !Bun.deepEquals(member.spec.compat, first.spec.compat))) continue;
|
|
1364
|
+
const routes = {};
|
|
1365
|
+
for (const member of group) if (member.tier === "none") routes.off = member.spec.id;
|
|
1366
|
+
else routes[member.tier] = member.spec.id;
|
|
1367
|
+
const efforts = THINKING_EFFORTS.filter((effort) => routes[effort] !== void 0);
|
|
1368
|
+
if (efforts.length === 0) continue;
|
|
1369
|
+
const strippedName = first.spec.name.replace(/\s+(extra-high|none|minimal|low|medium|high|xhigh|max)(\s+fast)?$/i, "").trim();
|
|
1370
|
+
const baseName = strippedName === first.spec.id ? first.baseId : strippedName || first.baseId;
|
|
1371
|
+
const suffix = first.fast ? "-fast" : "";
|
|
1372
|
+
families.push(tierFamily(`${first.baseId}${suffix}`, `${baseName}${first.fast ? " Fast" : ""}`, routes, efforts));
|
|
1373
|
+
}
|
|
1374
|
+
return families;
|
|
1375
|
+
}
|
|
1376
|
+
/** Provider id → reviewed collapse table. The CCA providers diverge on thinking transport. */
|
|
1377
|
+
const REVIEWED_COLLAPSE_TABLES = buildCompiledTables();
|
|
1378
|
+
/**
|
|
1379
|
+
* Return the reviewed collapse table compiled for `provider`, when declared.
|
|
1380
|
+
* Discovery uses this accessor to preserve injectable table seams.
|
|
1381
|
+
*/
|
|
1382
|
+
function reviewedCollapseTable(provider) {
|
|
1383
|
+
return REVIEWED_COLLAPSE_TABLES[provider] ?? REVIEWED_COLLAPSE_TABLES[provider.toLowerCase()];
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Logical id of the reviewed `provider` family claiming `memberId` as a member
|
|
1387
|
+
* or extra alias, or `undefined` when no reviewed family owns it. Cursor's rich
|
|
1388
|
+
* discovery names lanes with it so they keep the id the legacy-slug collapse
|
|
1389
|
+
* (and the bundled catalog) assigns.
|
|
1390
|
+
*/
|
|
1391
|
+
function reviewedVariantFamilyId(provider, memberId) {
|
|
1392
|
+
const table = reviewedCollapseTable(provider);
|
|
1393
|
+
return table ? getAliasIndex(table).resolve(memberId.trim()) : void 0;
|
|
1394
|
+
}
|
|
1395
|
+
/**
|
|
1396
|
+
* The global automatic rule: derive an `X` + `X-thinking` family for every
|
|
1397
|
+
* pair where both ids are live in `specs` (trailing or infix token). Gates:
|
|
1398
|
+
* - both members share the same `api`,
|
|
1399
|
+
* - known pricing must match — all-zero cost rows count as unknown
|
|
1400
|
+
* (aggregators routinely ship them), but twins that BOTH carry real,
|
|
1401
|
+
* differing prices are distinct SKUs and never merge,
|
|
1402
|
+
* - ids claimed by the provider's reviewed table are skipped (curation wins).
|
|
1403
|
+
* The capability surface prefers the thinking member's metadata, then the
|
|
1404
|
+
* bare member's, then the canonical deriver (aggregators often ship
|
|
1405
|
+
* `reasoning: false` and no thinking config on the twin), then a budget
|
|
1406
|
+
* default. `off` routes to the bare id; every supported effort routes to the
|
|
1407
|
+
* thinking id.
|
|
1408
|
+
*/
|
|
1409
|
+
function deriveThinkingPairFamilies(specs, table, provider) {
|
|
1410
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1411
|
+
for (const spec of specs) if (!byId.has(spec.id)) byId.set(spec.id, spec);
|
|
1412
|
+
const claimed = table ? getAliasIndex(table) : void 0;
|
|
1413
|
+
const families = [];
|
|
1414
|
+
for (const spec of specs) {
|
|
1415
|
+
const collapsed = provider === void 0 ? void 0 : collapseVariantId(provider, spec.id);
|
|
1416
|
+
const baseId = collapsed?.thinkingVariant ? collapsed.logicalId : stripThinkingVariantSuffix(spec.id);
|
|
1417
|
+
if (baseId === void 0 || baseId === spec.id) continue;
|
|
1418
|
+
const base = byId.get(baseId);
|
|
1419
|
+
if (!base) continue;
|
|
1420
|
+
if (claimed && (claimed.resolve(spec.id) !== void 0 || claimed.resolve(baseId) !== void 0 || claimed.isFamily(spec.id) || claimed.isFamily(baseId))) continue;
|
|
1421
|
+
if (spec.api !== base.api) continue;
|
|
1422
|
+
const specPriced = spec.cost.input !== 0 || spec.cost.output !== 0;
|
|
1423
|
+
const basePriced = base.cost.input !== 0 || base.cost.output !== 0;
|
|
1424
|
+
if (specPriced && basePriced && (spec.cost.input !== base.cost.input || spec.cost.output !== base.cost.output || spec.cost.cacheRead !== base.cost.cacheRead || spec.cost.cacheWrite !== base.cost.cacheWrite)) continue;
|
|
1425
|
+
const surface = derivePairThinkingSurface(spec, base);
|
|
1426
|
+
const routing = { off: base.id };
|
|
1427
|
+
for (const effort of surface.efforts) routing[effort] = spec.id;
|
|
1428
|
+
families.push({
|
|
1429
|
+
id: base.id,
|
|
1430
|
+
name: base.name,
|
|
1431
|
+
members: [base.id, spec.id],
|
|
1432
|
+
routing,
|
|
1433
|
+
thinking: surface
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
return families;
|
|
1437
|
+
}
|
|
1438
|
+
function derivePairThinkingSurface(thinkingSpec, baseSpec) {
|
|
1439
|
+
const baked = thinkingSpec.thinking ?? baseSpec.thinking;
|
|
1440
|
+
if (baked && baked.efforts.length > 0) {
|
|
1441
|
+
const { effortRouting: _routing, suppressWhenOff: _suppress, requiresEffort: _required, ...surface } = baked;
|
|
1442
|
+
return surface;
|
|
1443
|
+
}
|
|
1444
|
+
const { compat: _compat, ...policySpec } = thinkingSpec;
|
|
1445
|
+
const derived = resolveModelPolicy({
|
|
1446
|
+
...policySpec,
|
|
1447
|
+
reasoning: true,
|
|
1448
|
+
thinking: void 0
|
|
1449
|
+
}).thinking;
|
|
1450
|
+
if (derived && derived.efforts.length > 0) {
|
|
1451
|
+
const { effortRouting: _dRouting, suppressWhenOff: _dSuppress, requiresEffort: _dRequired, ...surface } = derived;
|
|
1452
|
+
return surface;
|
|
1453
|
+
}
|
|
1454
|
+
return {
|
|
1455
|
+
mode: "budget",
|
|
1456
|
+
efforts: DEFAULT_PAIR_EFFORTS
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
/**
|
|
1460
|
+
* Re-point a stale collapsed spec whose `requestModelId` or routing still
|
|
1461
|
+
* targets a retired wire id. Collapsed snapshots (bundled catalog, cache
|
|
1462
|
+
* rows, previous-generation fallbacks) pass through collapsing untouched, so
|
|
1463
|
+
* a reviewed-table routing fix would otherwise never reach them. Only retired
|
|
1464
|
+
* targets are rewritten — presence-filtered routing decisions from live
|
|
1465
|
+
* discovery stay authoritative for everything else. Per retired entry the
|
|
1466
|
+
* table's route for that effort wins, then the off/first-live-member wire id,
|
|
1467
|
+
* then the route is dropped (falls back to `requestModelId ?? id`). Returns
|
|
1468
|
+
* `spec` by reference when nothing targets a retired id.
|
|
1469
|
+
*/
|
|
1470
|
+
function reconcileRetiredRouting(spec, family, retired) {
|
|
1471
|
+
const currentThinking = spec.thinking;
|
|
1472
|
+
const routing = currentThinking?.effortRouting;
|
|
1473
|
+
const requestRetired = spec.requestModelId !== void 0 && retired.has(spec.requestModelId);
|
|
1474
|
+
let routingRetired = false;
|
|
1475
|
+
if (routing !== void 0) for (const key of VARIANT_ROUTING_KEYS) {
|
|
1476
|
+
const target = routing[key];
|
|
1477
|
+
if (target !== void 0 && retired.has(target)) {
|
|
1478
|
+
routingRetired = true;
|
|
1479
|
+
break;
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
if (!requestRetired && !routingRetired) return spec;
|
|
1483
|
+
const offTarget = family.routing.off;
|
|
1484
|
+
const fallbackWireId = offTarget !== void 0 && !retired.has(offTarget) ? offTarget : family.members.find((id) => !retired.has(id));
|
|
1485
|
+
const next = { ...spec };
|
|
1486
|
+
if (routingRetired && routing !== void 0 && currentThinking !== void 0) {
|
|
1487
|
+
const nextRouting = {};
|
|
1488
|
+
for (const effortKey of VARIANT_ROUTING_KEYS) {
|
|
1489
|
+
const target = routing[effortKey];
|
|
1490
|
+
if (target === void 0) continue;
|
|
1491
|
+
if (!retired.has(target)) {
|
|
1492
|
+
nextRouting[effortKey] = target;
|
|
1493
|
+
continue;
|
|
1494
|
+
}
|
|
1495
|
+
const tableTarget = family.routing[effortKey];
|
|
1496
|
+
if (tableTarget !== void 0 && !retired.has(tableTarget)) nextRouting[effortKey] = tableTarget;
|
|
1497
|
+
else if (fallbackWireId !== void 0) nextRouting[effortKey] = fallbackWireId;
|
|
1498
|
+
}
|
|
1499
|
+
next.thinking = {
|
|
1500
|
+
...currentThinking,
|
|
1501
|
+
effortRouting: nextRouting
|
|
1502
|
+
};
|
|
1503
|
+
}
|
|
1504
|
+
if (requestRetired) {
|
|
1505
|
+
if (fallbackWireId !== void 0 && fallbackWireId !== spec.id) next.requestModelId = fallbackWireId;
|
|
1506
|
+
else delete next.requestModelId;
|
|
1507
|
+
}
|
|
1508
|
+
return next;
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1511
|
+
* Refresh a collapsed snapshot's thinking surface in place. Bundled catalog and
|
|
1512
|
+
* prev-generation snapshots freeze a family's transport, budgets, and routing;
|
|
1513
|
+
* discovery emits the canonical id but the exact-id merge never overwrites a
|
|
1514
|
+
* stale `family.id` row (e.g. `gemini-3.1-pro`) nor a recycled `extraAliases`
|
|
1515
|
+
* row (e.g. `gemini-3-flash`). This re-applies the reviewed-table family's thinking,
|
|
1516
|
+
* routing, and default wire id while keeping the spec id (load-bearing for exact
|
|
1517
|
+
* selectors and bundled lookups). Returns `spec` by reference when unchanged.
|
|
1518
|
+
*/
|
|
1519
|
+
function refreshCollapsedThinking(spec, family, retired) {
|
|
1520
|
+
const familyThinking = family.thinking;
|
|
1521
|
+
if (!spec.reasoning || familyThinking?.effortBudgets === void 0) return spec;
|
|
1522
|
+
const routing = {};
|
|
1523
|
+
let hasRouting = false;
|
|
1524
|
+
for (const effortKey of VARIANT_ROUTING_KEYS) {
|
|
1525
|
+
const target = family.routing[effortKey];
|
|
1526
|
+
if (target !== void 0 && !retired?.has(target)) {
|
|
1527
|
+
routing[effortKey] = target;
|
|
1528
|
+
hasRouting = true;
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
const thinking = { ...familyThinking };
|
|
1532
|
+
if (hasRouting) thinking.effortRouting = routing;
|
|
1533
|
+
if (family.suppressWhenOff) thinking.suppressWhenOff = true;
|
|
1534
|
+
const offTarget = family.routing.off;
|
|
1535
|
+
const requestModelId = offTarget !== void 0 && !retired?.has(offTarget) && offTarget !== spec.id ? offTarget : spec.requestModelId;
|
|
1536
|
+
if (Bun.deepEquals(thinking, spec.thinking) && requestModelId === spec.requestModelId) return spec;
|
|
1537
|
+
return {
|
|
1538
|
+
...spec,
|
|
1539
|
+
thinking,
|
|
1540
|
+
...requestModelId !== void 0 ? { requestModelId } : {}
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Re-point a collapsed snapshot's default wire id to the family's declared
|
|
1545
|
+
* {@link EffortVariantFamily.defaultMember} when the snapshot still advertises a
|
|
1546
|
+
* different default. Bundled catalog and cache rows freeze `requestModelId` from
|
|
1547
|
+
* before a family gained a preferred default (Cursor Grok 4.5/4.6 → `-medium`),
|
|
1548
|
+
* and neither the existing-collapsed pass-through nor `refreshCollapsedThinking`
|
|
1549
|
+
* (scoped to `effortBudgets` families) would otherwise correct them — leaving an
|
|
1550
|
+
* effort-less request clamped to the refused `-low` tier (issue #9478). Only
|
|
1551
|
+
* re-points when the target is a live route in the snapshot's own
|
|
1552
|
+
* `effortRouting`. Returns `spec` by reference when unchanged.
|
|
1553
|
+
*/
|
|
1554
|
+
function reconcileDefaultMember(spec, family, presentMembers) {
|
|
1555
|
+
const defaultMember = family.defaultMember;
|
|
1556
|
+
if (defaultMember === void 0 || defaultMember === spec.id) return spec;
|
|
1557
|
+
const target = presentMembers === void 0 || presentMembers.has(defaultMember) ? defaultMember : family.members.find((id) => presentMembers.has(id));
|
|
1558
|
+
if (target === void 0 || spec.requestModelId === target) return spec;
|
|
1559
|
+
const routing = spec.thinking?.effortRouting;
|
|
1560
|
+
if (routing === void 0) return spec;
|
|
1561
|
+
for (const key of VARIANT_ROUTING_KEYS) if (routing[key] === target) return {
|
|
1562
|
+
...spec,
|
|
1563
|
+
requestModelId: target
|
|
1564
|
+
};
|
|
1565
|
+
return spec;
|
|
1566
|
+
}
|
|
1567
|
+
/**
|
|
1568
|
+
* Whether a Cursor wire id names an extended tier that upstream serves only in
|
|
1569
|
+
* max mode. The compiled taxonomy identifies `xhigh`/`extra-high`/`max`
|
|
1570
|
+
* efforts and their optional service lanes. This is an inference, not an
|
|
1571
|
+
* upstream marker: it is the only per-tier signal available for bundled rows
|
|
1572
|
+
* and for routes live discovery never advertised.
|
|
1573
|
+
*/
|
|
1574
|
+
function isCursorMaxModeWireId(wireModelId) {
|
|
1575
|
+
const effort = collapseVariantId("cursor", wireModelId).effort;
|
|
1576
|
+
return effort === "xhigh" || effort === "max";
|
|
1577
|
+
}
|
|
1578
|
+
/**
|
|
1579
|
+
* Recover Cursor's max-mode marker for a bundled collapsed row. The bundled
|
|
1580
|
+
* snapshot may contain only the logical row, but its effort routing still
|
|
1581
|
+
* records the wire ids, so {@link isCursorMaxModeWireId} preserves the
|
|
1582
|
+
* transport invariant even when live discovery contributes no raw members.
|
|
1583
|
+
*/
|
|
1584
|
+
function reconcileCursorMaxModeFromRouting(spec) {
|
|
1585
|
+
if (spec.provider !== "cursor" || spec.cursorMaxMode === true) return spec;
|
|
1586
|
+
const routing = spec.thinking?.effortRouting;
|
|
1587
|
+
if (routing === void 0) return spec;
|
|
1588
|
+
return Object.values(routing).some((target) => typeof target === "string" && isCursorMaxModeWireId(target)) ? {
|
|
1589
|
+
...spec,
|
|
1590
|
+
cursorMaxMode: true
|
|
1591
|
+
} : spec;
|
|
1592
|
+
}
|
|
1593
|
+
/**
|
|
1594
|
+
* Index the discovered `max_mode` marker of every live Cursor member by its own
|
|
1595
|
+
* wire id. The collapsed row's `cursorMaxMode` is an OR across members, so it
|
|
1596
|
+
* says nothing per tier; the transport needs the marker addressable by the wire
|
|
1597
|
+
* id it actually sends, because upstream marks tiers the slug cannot identify
|
|
1598
|
+
* (the whole Opus `-fast` lane is max-mode, `-low-fast` included). Returns
|
|
1599
|
+
* `undefined` when no member carries a marker, so unmarked rosters add no field.
|
|
1600
|
+
*/
|
|
1601
|
+
function cursorMaxModeRoutesOf(provider, memberSpecs) {
|
|
1602
|
+
if (provider !== "cursor") return void 0;
|
|
1603
|
+
let routes;
|
|
1604
|
+
for (const member of memberSpecs) {
|
|
1605
|
+
if (member.cursorMaxMode === void 0) continue;
|
|
1606
|
+
routes ??= {};
|
|
1607
|
+
routes[member.id] = member.cursorMaxMode;
|
|
1608
|
+
}
|
|
1609
|
+
return routes;
|
|
1610
|
+
}
|
|
1611
|
+
/**
|
|
1612
|
+
* Lift Cursor's max-mode markers from live member rows onto an already-collapsed
|
|
1613
|
+
* snapshot. Bundled catalog and cache rows froze the flag from `memberSpecs[0]`
|
|
1614
|
+
* — the `-none`/`-low` tier — so the committed `gpt-5.6-*` / `cursor-grok-*`
|
|
1615
|
+
* rows carry `cursorMaxMode: false`. The existing-collapsed pass-through keeps
|
|
1616
|
+
* the snapshot verbatim, so a live `GetUsableModels` roster that marks the
|
|
1617
|
+
* `-xhigh`/`-max` tiers would be discarded and max-tier requests would keep
|
|
1618
|
+
* sending `max_mode: false` on a max-mode-only wire id. The row-level flag
|
|
1619
|
+
* mirrors the fresh-collapse aggregation: only the positive case is lifted, so
|
|
1620
|
+
* a roster that marks nothing leaves the snapshot alone. The per-wire-id
|
|
1621
|
+
* markers are merged on top of the snapshot's own so live rows win per route.
|
|
1622
|
+
* Returns `spec` by reference when unchanged.
|
|
1623
|
+
*/
|
|
1624
|
+
function reconcileCursorMaxMode(spec, memberSpecs) {
|
|
1625
|
+
const routes = cursorMaxModeRoutesOf(spec.provider, memberSpecs);
|
|
1626
|
+
const lifts = spec.cursorMaxMode !== true && memberSpecs.some((member) => member.cursorMaxMode === true);
|
|
1627
|
+
if (routes === void 0 && !lifts) return spec;
|
|
1628
|
+
return {
|
|
1629
|
+
...spec,
|
|
1630
|
+
...lifts ? { cursorMaxMode: true } : {},
|
|
1631
|
+
...routes === void 0 ? {} : { cursorMaxModeRoutes: {
|
|
1632
|
+
...spec.cursorMaxModeRoutes,
|
|
1633
|
+
...routes
|
|
1634
|
+
} }
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* Collapse every family in `table` found in `specs`. Non-member specs pass
|
|
1639
|
+
* through verbatim (by reference), order preserved; the collapsed spec
|
|
1640
|
+
* replaces the first occurrence of its family.
|
|
1641
|
+
*/
|
|
1642
|
+
function collapseWithTable(specs, table) {
|
|
1643
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1644
|
+
for (const spec of specs) if (!byId.has(spec.id)) byId.set(spec.id, spec);
|
|
1645
|
+
/** family id → spec to emit at the family's first occurrence. */
|
|
1646
|
+
const replacement = /* @__PURE__ */ new Map();
|
|
1647
|
+
/** spec ids that belong to a touched family (members + logical id). */
|
|
1648
|
+
const familyIdBySpecId = /* @__PURE__ */ new Map();
|
|
1649
|
+
const instantiated = instantiateTemplates(table, byId.keys());
|
|
1650
|
+
const families = instantiated.length === 0 ? table.families : [...table.families, ...instantiated];
|
|
1651
|
+
for (const family of families) {
|
|
1652
|
+
const retired = family.retiredMembers !== void 0 && family.retiredMembers.length > 0 ? new Set(family.retiredMembers) : void 0;
|
|
1653
|
+
const existing = byId.get(family.id);
|
|
1654
|
+
const existingCollapsed = existing !== void 0 && (existing.requestModelId !== void 0 || existing.thinking?.effortRouting !== void 0);
|
|
1655
|
+
const reconciled = existing !== void 0 && existingCollapsed && retired !== void 0 ? reconcileRetiredRouting(existing, family, retired) : existing;
|
|
1656
|
+
const rawPresent = family.members.filter((id) => byId.has(id) && !(id === family.id && existingCollapsed));
|
|
1657
|
+
if (rawPresent.length === 0) {
|
|
1658
|
+
const refreshed = existing !== void 0 && existingCollapsed ? reconcileCursorMaxModeFromRouting(reconcileDefaultMember(refreshCollapsedThinking(reconciled ?? existing, family, retired), family)) : reconciled;
|
|
1659
|
+
if (refreshed !== void 0 && refreshed !== existing) {
|
|
1660
|
+
familyIdBySpecId.set(family.id, family.id);
|
|
1661
|
+
replacement.set(family.id, refreshed);
|
|
1662
|
+
}
|
|
1663
|
+
continue;
|
|
1664
|
+
}
|
|
1665
|
+
for (const id of rawPresent) familyIdBySpecId.set(id, family.id);
|
|
1666
|
+
if (existing) familyIdBySpecId.set(family.id, family.id);
|
|
1667
|
+
const memberSpecs = [];
|
|
1668
|
+
for (const id of rawPresent) {
|
|
1669
|
+
const member = byId.get(id);
|
|
1670
|
+
if (member !== void 0) memberSpecs.push(member);
|
|
1671
|
+
}
|
|
1672
|
+
if (existingCollapsed && reconciled !== void 0) {
|
|
1673
|
+
replacement.set(family.id, reconcileCursorMaxMode(reconcileDefaultMember(reconciled, family, new Set(rawPresent)), memberSpecs));
|
|
1674
|
+
continue;
|
|
1675
|
+
}
|
|
1676
|
+
const firstMember = memberSpecs[0];
|
|
1677
|
+
if (firstMember === void 0) continue;
|
|
1678
|
+
const presentSet = new Set(rawPresent);
|
|
1679
|
+
const routing = {};
|
|
1680
|
+
let hasRouting = false;
|
|
1681
|
+
let hasEffortRoute = false;
|
|
1682
|
+
let usedAbsentEffortRoute = false;
|
|
1683
|
+
for (const effort of VARIANT_ROUTING_KEYS) {
|
|
1684
|
+
const target = family.routing[effort];
|
|
1685
|
+
const targetPresent = target !== void 0 && presentSet.has(target);
|
|
1686
|
+
const preserveAbsentEffort = target !== void 0 && effort !== "off" && family.preserveAbsentEffortRoutes === true;
|
|
1687
|
+
if (target !== void 0 && (targetPresent || preserveAbsentEffort) && !retired?.has(target)) {
|
|
1688
|
+
routing[effort] = target;
|
|
1689
|
+
hasRouting = true;
|
|
1690
|
+
if (effort !== "off") hasEffortRoute = true;
|
|
1691
|
+
if (!targetPresent && effort !== "off") usedAbsentEffortRoute = true;
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
const reasoning = memberSpecs.some((spec) => spec.reasoning) || hasEffortRoute;
|
|
1695
|
+
const familyThinking = family.thinking;
|
|
1696
|
+
const thinking = familyThinking ? { ...familyThinking } : void 0;
|
|
1697
|
+
if (thinking !== void 0) {
|
|
1698
|
+
if (hasRouting) thinking.effortRouting = routing;
|
|
1699
|
+
if (family.suppressWhenOff) thinking.suppressWhenOff = true;
|
|
1700
|
+
}
|
|
1701
|
+
const input = [];
|
|
1702
|
+
if (memberSpecs.some((spec) => spec.input.includes("text"))) input.push("text");
|
|
1703
|
+
if (memberSpecs.some((spec) => spec.input.includes("image"))) input.push("image");
|
|
1704
|
+
const cursorMaxMode = memberSpecs.some((spec) => spec.cursorMaxMode === true) ? true : void 0;
|
|
1705
|
+
const cursorMaxModeRoutes = cursorMaxModeRoutesOf(firstMember.provider, memberSpecs);
|
|
1706
|
+
const collapsed = {
|
|
1707
|
+
...firstMember,
|
|
1708
|
+
id: family.id,
|
|
1709
|
+
name: family.name,
|
|
1710
|
+
reasoning,
|
|
1711
|
+
input,
|
|
1712
|
+
contextWindow: maxOrNull(memberSpecs.map((spec) => spec.contextWindow)),
|
|
1713
|
+
maxTokens: maxOrNull(memberSpecs.map((spec) => spec.maxTokens)),
|
|
1714
|
+
...cursorMaxMode === void 0 ? {} : { cursorMaxMode },
|
|
1715
|
+
...cursorMaxModeRoutes === void 0 ? {} : { cursorMaxModeRoutes }
|
|
1716
|
+
};
|
|
1717
|
+
if (memberSpecs.some((spec) => spec.isProviderDefault === true)) collapsed.isProviderDefault = true;
|
|
1718
|
+
const defaultWireId = (family.defaultMember !== void 0 && presentSet.has(family.defaultMember) && !retired?.has(family.defaultMember) ? family.defaultMember : void 0) ?? rawPresent.find((id) => !retired?.has(id)) ?? rawPresent[0];
|
|
1719
|
+
if (defaultWireId === void 0) continue;
|
|
1720
|
+
if (defaultWireId === family.id) {
|
|
1721
|
+
if (usedAbsentEffortRoute) collapsed.requestModelId = defaultWireId;
|
|
1722
|
+
else delete collapsed.requestModelId;
|
|
1723
|
+
} else collapsed.requestModelId = defaultWireId;
|
|
1724
|
+
if (reasoning && thinking !== void 0) collapsed.thinking = thinking;
|
|
1725
|
+
else delete collapsed.thinking;
|
|
1726
|
+
replacement.set(family.id, collapsed);
|
|
1727
|
+
}
|
|
1728
|
+
for (const family of table.families) {
|
|
1729
|
+
if (family.extraAliases === void 0) continue;
|
|
1730
|
+
const retired = family.retiredMembers !== void 0 && family.retiredMembers.length > 0 ? new Set(family.retiredMembers) : void 0;
|
|
1731
|
+
for (const alias of family.extraAliases) {
|
|
1732
|
+
if (alias === family.id || familyIdBySpecId.has(alias)) continue;
|
|
1733
|
+
const aliasSpec = byId.get(alias);
|
|
1734
|
+
if (aliasSpec === void 0) continue;
|
|
1735
|
+
const refreshed = refreshCollapsedThinking(aliasSpec, family, retired);
|
|
1736
|
+
if (refreshed !== aliasSpec) {
|
|
1737
|
+
familyIdBySpecId.set(alias, alias);
|
|
1738
|
+
replacement.set(alias, refreshed);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
if (replacement.size === 0) return [...specs];
|
|
1743
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
1744
|
+
const out = [];
|
|
1745
|
+
for (const spec of specs) {
|
|
1746
|
+
const familyId = familyIdBySpecId.get(spec.id);
|
|
1747
|
+
if (familyId === void 0) {
|
|
1748
|
+
out.push(spec);
|
|
1749
|
+
continue;
|
|
1750
|
+
}
|
|
1751
|
+
if (emitted.has(familyId)) continue;
|
|
1752
|
+
emitted.add(familyId);
|
|
1753
|
+
const familySpec = replacement.get(familyId);
|
|
1754
|
+
if (familySpec !== void 0) out.push(familySpec);
|
|
1755
|
+
}
|
|
1756
|
+
return out;
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Re-key model-to-model configuration after collapse removes a referenced
|
|
1760
|
+
* member id. Qualified targets keep their provider; bare targets remain bare.
|
|
1761
|
+
*/
|
|
1762
|
+
function retargetCollapsedModelReferences(specs) {
|
|
1763
|
+
const liveIdsByProvider = /* @__PURE__ */ new Map();
|
|
1764
|
+
for (const spec of specs) {
|
|
1765
|
+
const provider = spec.provider.toLowerCase();
|
|
1766
|
+
let liveIds = liveIdsByProvider.get(provider);
|
|
1767
|
+
if (!liveIds) {
|
|
1768
|
+
liveIds = /* @__PURE__ */ new Set();
|
|
1769
|
+
liveIdsByProvider.set(provider, liveIds);
|
|
1770
|
+
}
|
|
1771
|
+
liveIds.add(spec.id.toLowerCase());
|
|
1772
|
+
}
|
|
1773
|
+
for (let index = 0; index < specs.length; index++) {
|
|
1774
|
+
const spec = specs[index];
|
|
1775
|
+
if (!spec) continue;
|
|
1776
|
+
const contextPromotionTarget = resolveCollapsedModelReference(spec.contextPromotionTarget, spec.provider, liveIdsByProvider);
|
|
1777
|
+
const compactionModel = resolveCollapsedModelReference(spec.compactionModel, spec.provider, liveIdsByProvider);
|
|
1778
|
+
const webSearchModel = resolveCollapsedModelReference(spec.webSearchModel, spec.provider, liveIdsByProvider);
|
|
1779
|
+
const imageModel = resolveCollapsedModelReference(spec.imageModel, spec.provider, liveIdsByProvider);
|
|
1780
|
+
if (contextPromotionTarget === spec.contextPromotionTarget && compactionModel === spec.compactionModel && webSearchModel === spec.webSearchModel && imageModel === spec.imageModel) continue;
|
|
1781
|
+
specs[index] = {
|
|
1782
|
+
...spec,
|
|
1783
|
+
contextPromotionTarget,
|
|
1784
|
+
compactionModel,
|
|
1785
|
+
webSearchModel,
|
|
1786
|
+
imageModel
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
function resolveCollapsedModelReference(target, currentProvider, liveIdsByProvider) {
|
|
1791
|
+
if (target === void 0) return void 0;
|
|
1792
|
+
const separator = target.indexOf("/");
|
|
1793
|
+
const provider = separator >= 0 ? target.slice(0, separator) : currentProvider;
|
|
1794
|
+
const providerId = provider.toLowerCase();
|
|
1795
|
+
const normalizedModelId = (separator >= 0 ? target.slice(separator + 1) : target).trim().toLowerCase();
|
|
1796
|
+
const liveIds = liveIdsByProvider.get(providerId);
|
|
1797
|
+
if (liveIds?.has(normalizedModelId)) return target;
|
|
1798
|
+
const alias = resolveRegisteredVariantAlias(provider, normalizedModelId);
|
|
1799
|
+
if (alias === void 0 || !liveIds?.has(alias.toLowerCase())) return target;
|
|
1800
|
+
return separator >= 0 ? `${provider}/${alias}` : alias;
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Collapse a full mixed-provider list: per provider, the compiled reviewed table, Cursor's
|
|
1804
|
+
* conservative live effort-sibling rule, and the automatic `X`/`X-thinking`
|
|
1805
|
+
* pair rule. Used by the catalog generator; the runtime equivalent lives at
|
|
1806
|
+
* the model-manager merge point. Output is regrouped by provider — callers
|
|
1807
|
+
* re-sort.
|
|
1808
|
+
*/
|
|
1809
|
+
function collapseVariants(specs, opts) {
|
|
1810
|
+
if (opts?.table !== void 0) return collapseWithTable(specs, opts.table);
|
|
1811
|
+
const byProvider = /* @__PURE__ */ new Map();
|
|
1812
|
+
for (const spec of specs) {
|
|
1813
|
+
const slice = byProvider.get(spec.provider);
|
|
1814
|
+
if (slice) slice.push(spec);
|
|
1815
|
+
else byProvider.set(spec.provider, [spec]);
|
|
1816
|
+
}
|
|
1817
|
+
const out = [];
|
|
1818
|
+
for (const [provider, slice] of byProvider) {
|
|
1819
|
+
const table = reviewedCollapseTable(provider);
|
|
1820
|
+
let result = table ? collapseWithTable(slice, table) : slice;
|
|
1821
|
+
if (provider === "cursor") {
|
|
1822
|
+
const cursorDerived = deriveCursorEffortFamilies(result);
|
|
1823
|
+
if (cursorDerived.length > 0) result = collapseWithTable(result, { families: cursorDerived });
|
|
1824
|
+
}
|
|
1825
|
+
const derived = deriveThinkingPairFamilies(result, table, provider);
|
|
1826
|
+
if (derived.length > 0) result = collapseWithTable(result, { families: derived });
|
|
1827
|
+
registerCollapsedVariantAliases(provider, result);
|
|
1828
|
+
out.push(...result);
|
|
1829
|
+
}
|
|
1830
|
+
retargetCollapsedModelReferences(out);
|
|
1831
|
+
return out;
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Alias index over a collapse table (or the live families observed at
|
|
1835
|
+
* runtime). Templated families are materialized on first lookup of any id
|
|
1836
|
+
* they match, so a revision discovery has never advertised still resolves.
|
|
1837
|
+
*/
|
|
1838
|
+
var VariantAliasIndex = class {
|
|
1839
|
+
/** lowercased retired id → replacement model id. */
|
|
1840
|
+
#forward = /* @__PURE__ */ new Map();
|
|
1841
|
+
/**
|
|
1842
|
+
* lowercased provider-scoped alias → replacement model id. Kept apart from
|
|
1843
|
+
* `#forward` so bare-id and reverse lookups never see it.
|
|
1844
|
+
*/
|
|
1845
|
+
providerScoped = /* @__PURE__ */ new Map();
|
|
1846
|
+
/** replacement model id → retired ids that resolve to it. */
|
|
1847
|
+
#reverse = /* @__PURE__ */ new Map();
|
|
1848
|
+
/** Collapsed logical ids declared by the table or observed at runtime. */
|
|
1849
|
+
#familyIds = /* @__PURE__ */ new Set();
|
|
1850
|
+
#templates;
|
|
1851
|
+
constructor(templates = []) {
|
|
1852
|
+
this.#templates = templates;
|
|
1853
|
+
}
|
|
1854
|
+
/** Register `from` → `to`; false when `from` is already claimed. */
|
|
1855
|
+
add(from, to) {
|
|
1856
|
+
if (from === to || this.#forward.has(from.toLowerCase())) return false;
|
|
1857
|
+
this.#forward.set(from.toLowerCase(), to);
|
|
1858
|
+
const sources = this.#reverse.get(to);
|
|
1859
|
+
if (sources) sources.push(from);
|
|
1860
|
+
else this.#reverse.set(to, [from]);
|
|
1861
|
+
return true;
|
|
1862
|
+
}
|
|
1863
|
+
/** Register a family: its logical id plus every member and extra alias. */
|
|
1864
|
+
addFamily(family) {
|
|
1865
|
+
this.#familyIds.add(family.id);
|
|
1866
|
+
for (const member of family.members) this.add(member, family.id);
|
|
1867
|
+
for (const alias of family.extraAliases ?? []) this.add(alias, family.id);
|
|
1868
|
+
}
|
|
1869
|
+
markFamily(id) {
|
|
1870
|
+
this.#familyIds.add(id);
|
|
1871
|
+
}
|
|
1872
|
+
/** Replacement model id for a retired/member id (case-insensitive). */
|
|
1873
|
+
resolve(id) {
|
|
1874
|
+
const lower = id.toLowerCase();
|
|
1875
|
+
this.#learn(lower);
|
|
1876
|
+
return this.#forward.get(lower);
|
|
1877
|
+
}
|
|
1878
|
+
/** Whether `id` is a collapsed logical id of this index. */
|
|
1879
|
+
isFamily(id) {
|
|
1880
|
+
this.#learn(id);
|
|
1881
|
+
return this.#familyIds.has(id);
|
|
1882
|
+
}
|
|
1883
|
+
/** Retired ids that resolve to logical `id`. */
|
|
1884
|
+
sourcesOf(id) {
|
|
1885
|
+
this.#learn(id);
|
|
1886
|
+
return this.#reverse.get(id);
|
|
1887
|
+
}
|
|
1888
|
+
/** Materialize the template family that owns `id`, once. */
|
|
1889
|
+
#learn(id) {
|
|
1890
|
+
if (this.#templates.length === 0) return;
|
|
1891
|
+
const family = templateFamilyFor(this.#templates, id);
|
|
1892
|
+
if (family === void 0 || this.#familyIds.has(family.id)) return;
|
|
1893
|
+
this.addFamily(family);
|
|
1894
|
+
}
|
|
1895
|
+
};
|
|
1896
|
+
const dynamicAliasIndexes = /* @__PURE__ */ new Map();
|
|
1897
|
+
const kAliasIndex = Symbol("compat-collapse.aliasIndex");
|
|
1898
|
+
/**
|
|
1899
|
+
* Persist aliases embedded in collapsed routing so generated catalog rows and
|
|
1900
|
+
* newly discovered families expose the same selector migrations as reviewed tables.
|
|
1901
|
+
*/
|
|
1902
|
+
function registerCollapsedVariantAliases(provider, specs) {
|
|
1903
|
+
const providerId = provider.toLowerCase();
|
|
1904
|
+
let index = dynamicAliasIndexes.get(providerId);
|
|
1905
|
+
for (const spec of specs) {
|
|
1906
|
+
const routing = spec.thinking?.effortRouting;
|
|
1907
|
+
if (!routing) continue;
|
|
1908
|
+
let registered = false;
|
|
1909
|
+
for (const effort of VARIANT_ROUTING_KEYS) {
|
|
1910
|
+
const source = routing[effort];
|
|
1911
|
+
if (!source || source === spec.id) continue;
|
|
1912
|
+
index ??= new VariantAliasIndex();
|
|
1913
|
+
registered = index.add(source, spec.id) || registered;
|
|
1914
|
+
}
|
|
1915
|
+
if (spec.requestModelId && spec.requestModelId !== spec.id) {
|
|
1916
|
+
index ??= new VariantAliasIndex();
|
|
1917
|
+
registered = index.add(spec.requestModelId, spec.id) || registered;
|
|
1918
|
+
}
|
|
1919
|
+
if (registered) index?.markFamily(spec.id);
|
|
1920
|
+
}
|
|
1921
|
+
if (index) dynamicAliasIndexes.set(providerId, index);
|
|
1922
|
+
}
|
|
1923
|
+
function resolveRegisteredVariantAlias(provider, normalizedModelId) {
|
|
1924
|
+
const providerId = provider.toLowerCase();
|
|
1925
|
+
const table = reviewedCollapseTable(provider) ?? reviewedCollapseTable(providerId);
|
|
1926
|
+
return (table ? getAliasIndex(table).resolve(normalizedModelId) : void 0) ?? dynamicAliasIndexes.get(providerId)?.resolve(normalizedModelId);
|
|
1927
|
+
}
|
|
1928
|
+
function getAliasIndex(table) {
|
|
1929
|
+
const cached = Reflect.get(table, kAliasIndex);
|
|
1930
|
+
if (cached instanceof VariantAliasIndex) return cached;
|
|
1931
|
+
const index = new VariantAliasIndex(table.templates);
|
|
1932
|
+
for (const family of table.families) index.addFamily(family);
|
|
1933
|
+
for (const alias in table.providerAliases) {
|
|
1934
|
+
const target = table.providerAliases[alias];
|
|
1935
|
+
if (target !== void 0 && alias !== target) index.providerScoped.set(alias.toLowerCase(), target);
|
|
1936
|
+
}
|
|
1937
|
+
Reflect.set(table, kAliasIndex, index);
|
|
1938
|
+
return index;
|
|
1939
|
+
}
|
|
1940
|
+
function maxOrNull(values) {
|
|
1941
|
+
const known = values.filter((v) => v != null);
|
|
1942
|
+
return known.length ? Math.max(...known) : null;
|
|
1943
|
+
}
|
|
1944
|
+
//#endregion
|
|
1945
|
+
export { decodeJsonValue as a, pb as c, create as i, toBinary as l, isCursorMaxModeWireId as n, encodeJsonValue as o, reviewedVariantFamilyId as r, fromBinary as s, collapseVariants as t, buildModel as u };
|