@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.
Files changed (109) hide show
  1. package/lib/{abort-DZ54CaKU.mjs → abort-BTblp0Rt.mjs} +2 -2
  2. package/lib/{alibaba-coding-plan-DODpkcqi.mjs → alibaba-coding-plan-t3R4YKCB.mjs} +3 -3
  3. package/lib/{alibaba-token-plan-C6lpKCda.mjs → alibaba-token-plan-CO4djG1y.mjs} +4 -4
  4. package/lib/{alibaba-token-plan-CHGyWOfX.mjs → alibaba-token-plan-CUjYJX0-.mjs} +1 -1
  5. package/lib/{anthropic-Dv_GGX6g.mjs → anthropic-nf7w6so1.mjs} +48 -21
  6. package/lib/{api-key-validation-MnMf_ihX.mjs → api-key-validation-C_tZ7Y9a.mjs} +2 -2
  7. package/lib/behavior-BwvTUtag.mjs +111 -0
  8. package/lib/{browser-render-BZXt548F.mjs → browser-render-BQaEVK_n.mjs} +4 -4
  9. package/lib/{reference-CtvM4zLU.mjs → bundled-references-CrQ4dQcT.mjs} +57 -4
  10. package/lib/cascade-BWjRTD1q.mjs +30265 -0
  11. package/lib/{cline-pass-BT9CBEOj.mjs → cline-pass-Bjm-O8GG.mjs} +2 -2
  12. package/lib/cloudflare-CKXRJ0l9.mjs +37 -0
  13. package/lib/{cloudflare-ai-gateway-DReN6ohJ.mjs → cloudflare-ai-gateway-BpnBSjwV.mjs} +8 -4
  14. package/lib/cloudflare-workers-ai-odj9XswL.mjs +32 -0
  15. package/lib/collapse-_nkb2dn7.mjs +1945 -0
  16. package/lib/{coreweave-C82HrLpb.mjs → coreweave-CGDZOD8-.mjs} +1 -1
  17. package/lib/{coreweave-C68UgRQO.mjs → coreweave-DwffcgW5.mjs} +4 -4
  18. package/lib/cursor-BgOuV7Qf.mjs +794 -0
  19. package/lib/{cursor-_gHHq-Dq.mjs → cursor-CF1iHHbv.mjs} +68 -19
  20. package/lib/{cursor-proto-Cr_WEMuv.mjs → cursor-proto-BuNTjX3L.mjs} +823 -23
  21. package/lib/{devin-QpfTSl9H.mjs → devin-7OEeEb80.mjs} +112 -31
  22. package/lib/{devin-proto-DYhp4Ty6.mjs → devin-proto-C-QreeAv.mjs} +71 -5
  23. package/lib/{dom-DG3sPESc.mjs → dom-BmbZv4v9.mjs} +598 -182
  24. package/lib/{error-O63pC8zg.mjs → error-8LVo7tug.mjs} +725 -104
  25. package/lib/factory-droid-ChhmsGWb.mjs +71 -0
  26. package/lib/{fs-promises-shim-B2YFWkcd.mjs → fs-promises-shim-CANAxFWh.mjs} +10 -1
  27. package/lib/{github-copilot-BMEcw8N1.mjs → github-copilot-QwevdT30.mjs} +4 -4
  28. package/lib/{github-copilot-headers-DnjGEbko.mjs → github-copilot-headers-CAUZ0rUD.mjs} +138 -26
  29. package/lib/{gitlab-duo-DnHqJjFY.mjs → gitlab-duo-DigV7k_o.mjs} +2 -2
  30. package/lib/{google-antigravity-B1mSckrK.mjs → google-antigravity-D-oe0r8A.mjs} +6 -7
  31. package/lib/{google-gemini-cli-DJwThCCn.mjs → google-gemini-cli-CQBHgGJT.mjs} +5 -6
  32. package/lib/{google-oauth-shared-BctLpVUN.mjs → google-oauth-shared-CvgVIUwJ.mjs} +2 -2
  33. package/lib/google-validation-CdvRj4ec.mjs +126 -0
  34. package/lib/id-EJwVLDHE.mjs +2548 -0
  35. package/lib/index.mjs +248 -258
  36. package/lib/{kilo-BEgEwMJQ.mjs → kilo-5r6OffCa.mjs} +2 -2
  37. package/lib/{kimi-T9NldEIJ.mjs → kimi-DOOtbXmm.mjs} +9 -10
  38. package/lib/{launch-BIWNyrBB.mjs → launch-DkAjib7h.mjs} +1 -1
  39. package/lib/{markit-Dvp2JPdT.mjs → markit-CCcyeAds.mjs} +359 -140
  40. package/lib/{models-DnXMYGcJ.mjs → models-DCpDT_im.mjs} +199203 -112275
  41. package/lib/{muse-code-CNvqqAp6.mjs → muse-code-CYf8zj_B.mjs} +5 -5
  42. package/lib/{openai-codex-D5-CyTxa.mjs → openai-codex-Cj-TvSFh.mjs} +13 -10
  43. package/lib/{perplexity-A2PEoGaC.mjs → perplexity-Dh_Qgsmx.mjs} +68 -25
  44. package/lib/{pkce-BYjmugmw.mjs → pkce-DO-jBJLV.mjs} +1 -1
  45. package/lib/pricing-DusBEhwm.mjs +593 -0
  46. package/lib/{readability-uGhqb4GC.mjs → readability-XHK0o3bv.mjs} +287 -27
  47. package/lib/{scrapers-C1ujjV8k.mjs → scrapers-B6PADOVm.mjs} +13 -13
  48. package/lib/slugify-ynYWBIA5.mjs +11 -0
  49. package/lib/snowflake-B_jap6lz.mjs +666 -0
  50. package/lib/snowflake-Cu1ZyOp6.mjs +151 -0
  51. package/lib/{src-AELUUb5U.mjs → src-BhinCSpi.mjs} +1172 -458
  52. package/lib/{stream-AVOoe5Hj.mjs → stream-D2ivg3GH.mjs} +3740 -5311
  53. package/lib/{turndown-D6fof1OX.mjs → turndown-Vya8SavL.mjs} +82 -30
  54. package/lib/types/tools/hashline/native/index.d.ts +2 -2
  55. package/lib/types/tools/hashline/native/policy.d.ts +19 -21
  56. package/lib/types/tools/omp/session/agent-storage.d.ts +3 -3
  57. package/lib/types/tools/shared/bun-named-shim.d.ts +5 -0
  58. package/lib/{types-BLrLohwK.mjs → types-tH1v9uRm.mjs} +2 -2
  59. package/lib/{utils-cZX3f_Ls.mjs → utils-C_Ncya1r.mjs} +1737 -509
  60. package/lib/utils-D2tK38xq.mjs +34006 -0
  61. package/lib/{utils-I4I8azHN.mjs → utils-DrDwmNtu.mjs} +8 -3
  62. package/lib/{xai-oauth-CbeldUSV.mjs → xai-oauth-DLLzX6my.mjs} +4 -4
  63. package/lib/{xiaomi-Dl3VSs04.mjs → xiaomi-CqK-KivK.mjs} +2 -2
  64. package/lib/{zai-FyjGSypr.mjs → zai-DoJ2xPIH.mjs} +2 -2
  65. package/lib/{zip-DRrycScC.mjs → zip-DG1mUV6X.mjs} +1 -1
  66. package/package.json +8 -8
  67. package/lib/amazon-bedrock-Dx0rr9dY.mjs +0 -996
  68. package/lib/anthropic-ClCw0PV_.mjs +0 -3624
  69. package/lib/anthropic-wire-lbGAFzYb.mjs +0 -927
  70. package/lib/azure-openai-responses-WE_bgFWp.mjs +0 -285
  71. package/lib/bundled-references-DY3EJxZV.mjs +0 -56
  72. package/lib/cloudflare-ai-gateway-CrMa97Ap.mjs +0 -44
  73. package/lib/collapse-CkMNRNr7.mjs +0 -2304
  74. package/lib/cursor-C6jaIJDg.mjs +0 -283
  75. package/lib/cursor-D-XZYDf_.mjs +0 -4544
  76. package/lib/deterministic-id-CUEIMSqR.mjs +0 -17
  77. package/lib/devin-ExGIghmx.mjs +0 -69
  78. package/lib/devin-u0ljw5P6.mjs +0 -628
  79. package/lib/effort-BdtQMN-_.mjs +0 -23
  80. package/lib/event-stream-BKEtb45Y.mjs +0 -167
  81. package/lib/gemini-headers-Co9cVvex.mjs +0 -54
  82. package/lib/google-auth-qAN-6DMW.mjs +0 -232
  83. package/lib/google-gemini-cli-B2Aw1S5w.mjs +0 -844
  84. package/lib/google-lTxuq28n.mjs +0 -38
  85. package/lib/google-shared-Y01j9xOr.mjs +0 -856
  86. package/lib/google-validation-BEkNs-Bx.mjs +0 -18
  87. package/lib/google-vertex-DcM-FRC5.mjs +0 -99
  88. package/lib/hosts-00rjRzUD.mjs +0 -203
  89. package/lib/id-AL5obQzR.mjs +0 -71
  90. package/lib/idle-iterator-D0ZXEcUq.mjs +0 -366
  91. package/lib/ollama-6R0oXZks.mjs +0 -574
  92. package/lib/openai-codex-responses-C8bnBWOe.mjs +0 -3232
  93. package/lib/openai-completions-DNr3mUsn.mjs +0 -1430
  94. package/lib/openai-configuration-update-xMYUjaK_.mjs +0 -150
  95. package/lib/openai-reasoning-fallback-Ju-5pSR8.mjs +0 -380
  96. package/lib/openai-responses-CjpafAEr.mjs +0 -861
  97. package/lib/protobuf-BMgDYu_U.mjs +0 -717
  98. package/lib/provider-response-SqKSkkUc.mjs +0 -22
  99. package/lib/proxy-DxvCQOCA.mjs +0 -230
  100. package/lib/request-debug-BwPOqN_j.mjs +0 -183
  101. package/lib/sanitize-text-BCf5KmCf.mjs +0 -33
  102. package/lib/sse-debug-B-tkLCPW.mjs +0 -11
  103. package/lib/stream-markup-healing-CN3RsqG9.mjs +0 -267
  104. package/lib/strict-tool-validation-CBTz1dAA.mjs +0 -105
  105. package/lib/taxonomy-DSIM99rS.mjs +0 -15392
  106. package/lib/thinking-ngMwf_1Y.mjs +0 -336
  107. package/lib/type-guards-CttAANEx.mjs +0 -11
  108. package/lib/utils-CE3DSebh.mjs +0 -11763
  109. package/lib/vision-guard-BCpXWUj3.mjs +0 -77
@@ -0,0 +1,2548 @@
1
+ import { installBunShim as __installBunShim } from "./bun-shim.mjs";
2
+ __installBunShim();
3
+ import { c as compareRevision, h as isRecord, n as hasModelScopedEffortsRule, r as resolveCascade, u as parseRevision } from "./cascade-BWjRTD1q.mjs";
4
+ import "./utils-DrDwmNtu.mjs";
5
+ import { l as classifyModel, p as stripThinkingVariantSuffix } from "./pricing-DusBEhwm.mjs";
6
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/effort.ts
7
+ /** User-facing thinking levels, ordered least to most intensive. */
8
+ let Effort = /* @__PURE__ */ function(Effort) {
9
+ Effort["Minimal"] = "minimal";
10
+ Effort["Low"] = "low";
11
+ Effort["Medium"] = "medium";
12
+ Effort["High"] = "high";
13
+ Effort["XHigh"] = "xhigh";
14
+ Effort["Max"] = "max";
15
+ return Effort;
16
+ }({});
17
+ const THINKING_EFFORTS = [
18
+ "minimal",
19
+ "low",
20
+ "medium",
21
+ "high",
22
+ "xhigh",
23
+ "max"
24
+ ];
25
+ //#endregion
26
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/hosts.ts
27
+ const KNOWN_HOSTS = {
28
+ openai: {
29
+ providers: ["openai"],
30
+ urlMarkers: ["api.openai.com"]
31
+ },
32
+ /** URL-only: a Codex provider rerouted through a proxy does not imply the subscription backend's capabilities. */
33
+ openaiCodex: { urlMarkers: ["chatgpt.com/backend-api", "chat.openai.com/backend-api"] },
34
+ azureOpenAI: {
35
+ providers: ["azure"],
36
+ urlMarkers: [
37
+ ".openai.azure.com",
38
+ "azure.com/openai",
39
+ "models.inference.ai.azure.com"
40
+ ]
41
+ },
42
+ openrouter: {
43
+ providers: ["openrouter"],
44
+ urlMarkers: ["openrouter.ai"]
45
+ },
46
+ vercelAIGateway: {
47
+ providers: ["vercel-ai-gateway"],
48
+ urlMarkers: ["ai-gateway.vercel.sh"]
49
+ },
50
+ githubCopilot: {
51
+ providers: ["github-copilot"],
52
+ urlMarkers: ["githubcopilot.com", "copilot-api."]
53
+ },
54
+ anthropic: {
55
+ providers: ["anthropic"],
56
+ urlMarkers: ["api.anthropic.com"]
57
+ },
58
+ /** DeepSeek's first-party API only — gates direct-API quirks (max_tokens field, thinking extraBody). */
59
+ deepseekDirect: {
60
+ providers: ["deepseek"],
61
+ urlMarkers: ["api.deepseek.com"]
62
+ },
63
+ /** Any DeepSeek-operated host (first-party API, web-chat fronts). Wider than `deepseekDirect` on purpose. */
64
+ deepseekFamily: {
65
+ providers: ["deepseek"],
66
+ urlMarkers: ["deepseek.com"]
67
+ },
68
+ cerebras: {
69
+ providers: ["cerebras"],
70
+ urlMarkers: ["cerebras.ai"]
71
+ },
72
+ zai: {
73
+ providers: ["zai"],
74
+ urlMarkers: ["api.z.ai"]
75
+ },
76
+ zhipu: {
77
+ providers: ["zhipu-coding-plan"],
78
+ urlMarkers: ["open.bigmodel.cn"]
79
+ },
80
+ kilo: {
81
+ providers: ["kilo"],
82
+ urlMarkers: ["api.kilo.ai"]
83
+ },
84
+ alibabaDashscope: {
85
+ providers: ["alibaba-coding-plan", "alibaba-token-plan"],
86
+ urlMarkers: ["dashscope", "token-plan."]
87
+ },
88
+ umans: {
89
+ providers: ["umans"],
90
+ urlMarkers: ["api.code.umans.ai"]
91
+ },
92
+ xiaomi: {
93
+ providers: ["xiaomi"],
94
+ providerPrefixes: ["xiaomi-token-plan-"],
95
+ urlMarkers: ["xiaomimimo.com"]
96
+ },
97
+ xai: {
98
+ providers: ["xai", "xai-oauth"],
99
+ urlMarkers: ["api.x.ai"]
100
+ },
101
+ mistral: {
102
+ providers: ["mistral"],
103
+ urlMarkers: ["mistral.ai"]
104
+ },
105
+ together: {
106
+ providers: ["together"],
107
+ urlMarkers: ["api.together.xyz"]
108
+ },
109
+ baseten: {
110
+ providers: ["baseten"],
111
+ urlMarkers: ["baseten.co"]
112
+ },
113
+ /** URL-only on purpose: the `fireworks`/`firepass` providers route per-model and not every model is Fireworks-shaped. */
114
+ fireworks: { urlMarkers: ["fireworks.ai"] },
115
+ groq: {
116
+ providers: ["groq"],
117
+ urlMarkers: ["api.groq.com"]
118
+ },
119
+ minimax: {
120
+ providers: [
121
+ "minimax",
122
+ "minimax-code",
123
+ "minimax-code-cn"
124
+ ],
125
+ urlMarkers: ["api.minimax.io", "api.minimaxi.com"]
126
+ },
127
+ qwenPortal: {
128
+ providers: ["qwen-portal"],
129
+ urlMarkers: ["portal.qwen.ai"]
130
+ },
131
+ /** NVIDIA NIM (`integrate.api.nvidia.com`). Qwen NIM endpoints take `chat_template_kwargs.enable_thinking`, never top-level `enable_thinking`. */
132
+ nvidia: {
133
+ providers: ["nvidia"],
134
+ urlMarkers: ["integrate.api.nvidia.com"]
135
+ },
136
+ /** Venice AI (`api.venice.ai`). OpenAI-compatible; drives reasoning via top-level `reasoning_effort` (and `venice_parameters.disable_thinking`), and rejects DashScope's top-level `enable_thinking` with a 400 (`additionalProperties: false` request schema). */
137
+ venice: {
138
+ providers: ["venice"],
139
+ urlMarkers: ["api.venice.ai"]
140
+ },
141
+ moonshotNative: {
142
+ providers: ["moonshot", "kimi-code"],
143
+ urlMarkers: ["api.moonshot.ai", "api.kimi.com"]
144
+ },
145
+ /** Google AI Studio's OpenAI-compatible shim (`/v1beta/openai`) — a subset of chat-completions; rejects `store` with a 400. Native Gemini uses `google-generative-ai` api instead. */
146
+ googleAistudio: {
147
+ providers: [],
148
+ urlMarkers: ["generativelanguage.googleapis.com"]
149
+ },
150
+ opencode: {
151
+ providers: ["opencode-go", "opencode-zen"],
152
+ urlMarkers: ["opencode.ai"]
153
+ },
154
+ /** ZenMux's Anthropic-compatible proxy (`zenmux.ai/api/anthropic`) forwards to signature-enforcing Anthropic. */
155
+ zenmux: {
156
+ providers: ["zenmux"],
157
+ urlMarkers: ["zenmux.ai"]
158
+ },
159
+ chutes: { urlMarkers: ["chutes.ai"] }
160
+ };
161
+ const MAX_URL_HOST_MATCHES = 512;
162
+ const urlHostMatches = /* @__PURE__ */ new Map();
163
+ function getUrlHostMatches(baseUrl) {
164
+ let matches = urlHostMatches.get(baseUrl);
165
+ if (matches !== void 0) return matches;
166
+ if (urlHostMatches.size === MAX_URL_HOST_MATCHES) urlHostMatches.clear();
167
+ matches = /* @__PURE__ */ new Map();
168
+ urlHostMatches.set(baseUrl, matches);
169
+ return matches;
170
+ }
171
+ /** URL-only host check (for call sites that have no provider id, e.g. raw env config). */
172
+ function hostMatchesUrl(baseUrl, host) {
173
+ if (!baseUrl) return false;
174
+ const matches = getUrlHostMatches(baseUrl);
175
+ const cached = matches.get(host);
176
+ if (cached !== void 0) return cached;
177
+ const spec = KNOWN_HOSTS[host];
178
+ for (const marker of spec.urlMarkers) if (includesAsciiCaseInsensitive(baseUrl, marker)) {
179
+ matches.set(host, true);
180
+ return true;
181
+ }
182
+ matches.set(host, false);
183
+ return false;
184
+ }
185
+ /** Provider-or-URL host check — the canonical `provider === id || baseUrl.includes(marker)` idiom. */
186
+ function modelMatchesHost(model, host) {
187
+ const spec = KNOWN_HOSTS[host];
188
+ if (spec.providers) {
189
+ for (const provider of spec.providers) if (model.provider === provider) return true;
190
+ }
191
+ if (spec.providerPrefixes) {
192
+ for (const prefix of spec.providerPrefixes) if (model.provider.startsWith(prefix)) return true;
193
+ }
194
+ return hostMatchesUrl(model.baseUrl, host);
195
+ }
196
+ function includesAsciiCaseInsensitive(value, lowerNeedle) {
197
+ const needleLength = lowerNeedle.length;
198
+ const end = value.length - needleLength;
199
+ for (let start = 0; start <= end; start++) {
200
+ let offset = 0;
201
+ for (; offset < needleLength; offset++) if ((value.charCodeAt(start + offset) | 32) !== lowerNeedle.charCodeAt(offset)) break;
202
+ if (offset === needleLength) return true;
203
+ }
204
+ return false;
205
+ }
206
+ /**
207
+ * Hostname for a Vertex AI GenerateContent / rawPredict / OpenAI-compat
208
+ * request for the given location.
209
+ *
210
+ * - `global` → global endpoint (`aiplatform.googleapis.com`)
211
+ * - `eu` / `us` multi-regions → REP endpoints (`aiplatform.{eu|us}.rep.googleapis.com`)
212
+ * - every other location → regional (`{location}-aiplatform.googleapis.com`)
213
+ *
214
+ * Multi-region codes do NOT follow the regional `{location}-aiplatform` pattern;
215
+ * interpolating them that way yields hosts like `eu-aiplatform.googleapis.com`
216
+ * that 404.
217
+ */
218
+ function resolveVertexEndpointHost(location) {
219
+ if (location === "global") return "aiplatform.googleapis.com";
220
+ if (location === "eu" || location === "us") return `aiplatform.${location}.rep.googleapis.com`;
221
+ return `${location}-aiplatform.googleapis.com`;
222
+ }
223
+ /** Vertex AI Anthropic raw-predict endpoints (`:streamRawPredict` / `:rawPredict`). */
224
+ function isVertexRawPredictUrl(baseUrl) {
225
+ return baseUrl.includes(":streamRawPredict") || baseUrl.includes(":rawPredict");
226
+ }
227
+ const BEDROCK_PUBLIC_HOST = /^(?:(?<runtime>bedrock-runtime(?:-fips)?)\.[a-z0-9-]+\.amazonaws\.com|bedrock-mantle\.(?:[a-z0-9-]+|\{region\})\.api\.aws)$/;
228
+ const BEDROCK_PRIVATELINK_HOST = /^vpce-[a-z0-9-]+\.(?:(?<runtime>bedrock-runtime(?:-fips)?)|bedrock-mantle)\.[a-z0-9-]+\.vpce\.amazonaws\.com$/;
229
+ function hasPathPrefix(pathname, prefix) {
230
+ return pathname === prefix || pathname.startsWith(`${prefix}/`);
231
+ }
232
+ /**
233
+ * Amazon Bedrock API route on a bedrock-runtime or bedrock-mantle endpoint
234
+ * (public, FIPS, or PrivateLink hostname):
235
+ * - `anthropic`: the Anthropic Messages API under `/anthropic`.
236
+ * - `openai`: the OpenAI-compatible APIs under `/openai`, plus Mantle's
237
+ * documented `/v1` base (`https://bedrock-mantle.<region>.api.aws/v1`).
238
+ * - `runtime`: the bedrock-runtime origin itself, where Converse and
239
+ * InvokeModel live under `/model/<id>/…`.
240
+ *
241
+ * Hostnames are parsed strictly so proxies that embed these hosts in a path
242
+ * do not match.
243
+ */
244
+ function isBedrockRouteUrl(baseUrl, route) {
245
+ if (!baseUrl) return false;
246
+ let url;
247
+ try {
248
+ url = new URL(baseUrl);
249
+ } catch {
250
+ return false;
251
+ }
252
+ if (url.protocol !== "https:") return false;
253
+ const host = BEDROCK_PUBLIC_HOST.exec(url.hostname) ?? BEDROCK_PRIVATELINK_HOST.exec(url.hostname);
254
+ if (!host) return false;
255
+ const isMantle = host.groups?.runtime === void 0;
256
+ if (route === "runtime") return !isMantle && url.pathname === "/";
257
+ if (route === "anthropic") return hasPathPrefix(url.pathname, "/anthropic");
258
+ return hasPathPrefix(url.pathname, "/openai") || isMantle && hasPathPrefix(url.pathname, "/v1");
259
+ }
260
+ //#endregion
261
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/model-thinking.ts
262
+ /**
263
+ * Returns the supported thinking efforts declared on the model metadata.
264
+ * Empty for non-reasoning models and for reasoning models without a
265
+ * controllable effort surface (`thinking: undefined`).
266
+ */
267
+ function getSupportedEfforts(model) {
268
+ if (!model.reasoning) return [];
269
+ return model.thinking?.efforts ?? [];
270
+ }
271
+ /**
272
+ * Neutral view of a model whose thinking ladder is unverified: `reasoning: false`
273
+ * and no ladder. Re-entering policy resolution starts from it (the ladder is
274
+ * derived output, not authored input), and requests without an effort send it so
275
+ * no reasoning or disable fields reach an upstream that may reject them.
276
+ */
277
+ function withoutUnverifiedThinking(model) {
278
+ if (!model.thinking?.unverified) return model;
279
+ const { thinking: _derived, ...rest } = model;
280
+ return {
281
+ ...rest,
282
+ reasoning: false
283
+ };
284
+ }
285
+ function requireSupportedEffort(model, effort) {
286
+ if (!model.reasoning) throw new Error(`Model ${model.provider}/${model.id} does not support thinking`);
287
+ const levels = getSupportedEfforts(model);
288
+ if (!levels.includes(effort)) throw new Error(`Thinking effort ${effort} is not supported by ${model.provider}/${model.id}. Supported efforts: ${levels.join(", ")}`);
289
+ return effort;
290
+ }
291
+ /**
292
+ * Maps a normalized thinking effort to Anthropic adaptive effort values via
293
+ * the model's baked `thinking.effortMap` (identity for unmapped efforts).
294
+ *
295
+ * The Anthropic adaptive wire vocabulary has no `minimal` tier (valid values:
296
+ * `low`, `medium`, `high`, `xhigh`, `max`); a model ladder that exposes
297
+ * `minimal` — custom `anthropic-messages` providers do, unlike the built-in
298
+ * Claude ladders — would otherwise serialize `output_config.effort: "minimal"`
299
+ * and 400 (`level "minimal" not supported`). Clamp it to the lowest real tier,
300
+ * mirroring {@link mapEffortToGoogleThinkingLevel}'s `minimal` handling.
301
+ */
302
+ function mapEffortToAnthropicAdaptiveEffort(model, effort) {
303
+ const supported = requireSupportedEffort(model, effort);
304
+ const mapped = model.thinking?.effortMap?.[supported] ?? supported;
305
+ if (mapped === "minimal") return "low";
306
+ return mapped;
307
+ }
308
+ /**
309
+ * Resolves the upstream wire model id for a request at the given effort
310
+ * (`undefined` = thinking off). Collapsed effort-tier variants route through
311
+ * `thinking.effortRouting`; everything else falls back to
312
+ * `requestModelId ?? id`.
313
+ */
314
+ function resolveWireModelId(model, effort) {
315
+ return model.thinking?.effortRouting?.[effort ?? "off"] ?? model.requestModelId ?? model.id;
316
+ }
317
+ //#endregion
318
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/wire/codex.ts
319
+ /**
320
+ * Constants for OpenAI Codex (ChatGPT OAuth) backend
321
+ */
322
+ const CODEX_BASE_URL = "https://chatgpt.com/backend-api";
323
+ const OFFICIAL_CODEX_URL = new URL(CODEX_BASE_URL);
324
+ /** Strict official-Codex endpoint check; exact origin or a path boundary after {@link CODEX_BASE_URL}. */
325
+ function isOfficialCodexApiUrl(baseUrl) {
326
+ if (!baseUrl) return true;
327
+ try {
328
+ const candidate = new URL(baseUrl);
329
+ const candidatePath = candidate.pathname.replace(/\/+$/, "");
330
+ return candidate.origin === OFFICIAL_CODEX_URL.origin && (candidatePath === OFFICIAL_CODEX_URL.pathname || candidatePath.startsWith(`${OFFICIAL_CODEX_URL.pathname}/`));
331
+ } catch {
332
+ return false;
333
+ }
334
+ }
335
+ /**
336
+ * Pinned OpenAI Codex client version (corresponds to @openai/codex package version).
337
+ * Updated from npm by `bun run check-spoofed-versions --update`.
338
+ *
339
+ * The backend version-gates model availability against this value on both
340
+ * `/models?client_version=` and `/responses`, independently of a model's
341
+ * declared `minimal_client_version`: GPT-6.1 Sol declares 0.153.0 yet is
342
+ * omitted from `/models` at 0.155.1 and listed at 0.159.0. An older pin
343
+ * silently hides newer SKUs from discovery.
344
+ */
345
+ const CODEX_CLIENT_VERSION = "0.159.0";
346
+ const OPENAI_HEADERS = {
347
+ BETA: "OpenAI-Beta",
348
+ /** Codex feature-negotiation header; values identify opt-in wire protocols. */
349
+ CODEX_BETA_FEATURES: "x-codex-beta-features",
350
+ ACCOUNT_ID: "chatgpt-account-id",
351
+ ORIGINATOR: "originator",
352
+ VERSION: "version",
353
+ SESSION_ID: "session_id",
354
+ CONVERSATION_ID: "conversation_id",
355
+ SCOPED_SESSION_ID: "session-id",
356
+ THREAD_ID: "thread-id",
357
+ INSTALLATION_ID: "x-codex-installation-id",
358
+ WINDOW_ID: "x-codex-window-id",
359
+ TURN_METADATA: "x-codex-turn-metadata",
360
+ PARENT_THREAD_ID: "x-codex-parent-thread-id",
361
+ SUBAGENT: "x-openai-subagent",
362
+ /** Responses Lite transport marker (codex-rs `add_responses_lite_header`); value is always `"true"`. */
363
+ RESPONSES_LITE: "x-openai-internal-codex-responses-lite",
364
+ /** DeviceCheck attestation envelope (codex-rs `X_OAI_ATTESTATION_HEADER`); sent on ChatGPT-OAuth requests. */
365
+ ATTESTATION: "x-oai-attestation",
366
+ /** Client-declared data residency for region-pinned enterprise workspaces. */
367
+ RESIDENCY: "x-openai-internal-codex-residency",
368
+ /**
369
+ * Model routing hint (codex-rs `X_CODEX_ROUTING_HINT_HEADER`): `model=<slug>`
370
+ * or `model=<slug>;tier=<service_tier>`; sent on every ChatGPT-OAuth
371
+ * Responses, compaction, and WebSocket handshake request. Built by
372
+ * {@link codexRoutingHint}.
373
+ */
374
+ ROUTING_HINT: "x-codex-routing-hint"
375
+ };
376
+ const OPENAI_HEADER_VALUES = {
377
+ BETA_RESPONSES: "responses=experimental",
378
+ BETA_RESPONSES_WEBSOCKETS_V2: "responses_websockets=2026-02-06",
379
+ REMOTE_COMPACTION_V2: "remote_compaction_v2",
380
+ ORIGINATOR_CODEX: "omp"
381
+ };
382
+ const JWT_CLAIM_PATH = "https://api.openai.com/auth";
383
+ /**
384
+ * Build the `x-codex-routing-hint` value for a request (codex-rs
385
+ * `build_routing_hint_header`): the requested model slug plus the explicit
386
+ * service tier when one is set. Callers set it only on ChatGPT-OAuth requests
387
+ * to the Codex backend; API-key OpenAI traffic never carries it.
388
+ */
389
+ function codexRoutingHint(model, serviceTier) {
390
+ return serviceTier ? `model=${model};tier=${serviceTier}` : `model=${model}`;
391
+ }
392
+ /**
393
+ * Extract account ID from a Codex JWT access token.
394
+ * Returns undefined if the token is not a valid Codex JWT.
395
+ */
396
+ function getCodexAccountId(accessToken) {
397
+ try {
398
+ const parts = accessToken.split(".");
399
+ if (parts.length !== 3) return void 0;
400
+ const decoded = Buffer.from(parts[1] ?? "", "base64").toString("utf-8");
401
+ return JSON.parse(decoded)["https://api.openai.com/auth"]?.chatgpt_account_id ?? void 0;
402
+ } catch {
403
+ return;
404
+ }
405
+ }
406
+ /** Residency claim value of an account that is not region-pinned. */
407
+ const CODEX_UNCONSTRAINED_RESIDENCY = "no_constraint";
408
+ /**
409
+ * Extract the account's data residency from a Codex JWT access token.
410
+ *
411
+ * Enterprise ChatGPT workspaces can be pinned to a region. Such a workspace
412
+ * rejects a Codex request whose egress does not match it — HTTP 401
413
+ * `Workspace is not authorized in this region.` — unless the client declares
414
+ * the residency itself. The token already carries it, so no configuration is
415
+ * needed: `chatgpt_data_residency` is the authoritative claim, with
416
+ * `chatgpt_compute_residency` as the fallback for tokens that only carry that.
417
+ *
418
+ * Returns undefined for a non-JWT token, or for the (common) accounts that are
419
+ * not region-pinned: their claims omit residency or carry the
420
+ * {@link CODEX_UNCONSTRAINED_RESIDENCY} sentinel. The backend answers 404 to a
421
+ * declared `no_constraint`, and codex-rs never sends it.
422
+ */
423
+ function getCodexResidency(accessToken) {
424
+ try {
425
+ const parts = accessToken.split(".");
426
+ if (parts.length !== 3) return void 0;
427
+ const decoded = Buffer.from(parts[1] ?? "", "base64").toString("utf-8");
428
+ const auth = JSON.parse(decoded)[JWT_CLAIM_PATH];
429
+ for (const claim of [auth?.chatgpt_data_residency, auth?.chatgpt_compute_residency]) {
430
+ if (typeof claim !== "string") continue;
431
+ const residency = claim.trim();
432
+ if (residency.length === 0) continue;
433
+ return residency.toLowerCase() === CODEX_UNCONSTRAINED_RESIDENCY ? void 0 : residency;
434
+ }
435
+ return;
436
+ } catch {
437
+ return;
438
+ }
439
+ }
440
+ /**
441
+ * Adds the token's workspace residency to Codex request headers without
442
+ * replacing a caller-supplied value.
443
+ */
444
+ function applyCodexResidencyHeader(headers, accessToken) {
445
+ const headerName = OPENAI_HEADERS.RESIDENCY;
446
+ if (headers instanceof Headers) {
447
+ if (headers.has(headerName)) return;
448
+ const residency = getCodexResidency(accessToken);
449
+ if (residency) headers.set(headerName, residency);
450
+ return;
451
+ }
452
+ for (const configuredName in headers) if (configuredName.toLowerCase() === headerName) return;
453
+ const residency = getCodexResidency(accessToken);
454
+ if (residency) headers[headerName] = residency;
455
+ }
456
+ //#endregion
457
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/compat/anthropic.ts
458
+ /**
459
+ * Anthropic endpoint-shape predicates: which URLs are the official first-party
460
+ * API, and which non-official hosts enforce Anthropic's thinking-signature
461
+ * protocol on replay. Compat resolution (`./resolve`) and runtime routing in
462
+ * pi-ai both consume these; URL matching is the one detection surface that
463
+ * stays in code.
464
+ */
465
+ const OFFICIAL_ANTHROPIC_URL = "https://api.anthropic.com";
466
+ /**
467
+ * Official first-party Anthropic API. A missing baseUrl is official on purpose:
468
+ * request dispatch falls back to `https://api.anthropic.com`. This is the one
469
+ * auth-sensitive host check — OAuth credentials are attached based on it — so
470
+ * it requires the exact origin or a path boundary (`/`) after it; a bare
471
+ * prefix check would accept lookalikes like `https://api.anthropic.com.evil.com`.
472
+ */
473
+ function isOfficialAnthropicApiUrl(baseUrl) {
474
+ if (!baseUrl) return true;
475
+ const lower = baseUrl.toLowerCase();
476
+ return lower === OFFICIAL_ANTHROPIC_URL || lower.startsWith(`${OFFICIAL_ANTHROPIC_URL}/`);
477
+ }
478
+ const CLOUDFLARE_ANTHROPIC_GATEWAY_URL_MARKER = /gateway\.ai\.cloudflare\.com\/.+\/anthropic(?:\/|$)/i;
479
+ const VERTEX_ANTHROPIC_URL_MARKER = /aiplatform\.googleapis\.com\/.+\/publishers\/anthropic\//i;
480
+ const BEDROCK_ANTHROPIC_URL_MARKER = /(?:^|\/\/|\.)bedrock-runtime\.[a-z0-9-]+\.amazonaws\.com/i;
481
+ const AZURE_ANTHROPIC_URL_MARKER = /(?:^|\/\/|\.)[a-z0-9-]+\.(?:inference|services)\.ai\.azure\.com/i;
482
+ /**
483
+ * Amazon Bedrock's Anthropic Messages API: the `/anthropic` path on the
484
+ * bedrock-runtime or bedrock-mantle endpoint. It rejects the tool `strict`
485
+ * field and enforces Anthropic signatures on replay.
486
+ */
487
+ function isBedrockAnthropicRoute(baseUrl) {
488
+ return isBedrockRouteUrl(baseUrl, "anthropic");
489
+ }
490
+ /**
491
+ * Azure AI Inference / Foundry Anthropic route
492
+ * (`<resource>.inference.ai.azure.com`, `<resource>.services.ai.azure.com`).
493
+ * Fronts Claude behind Azure identity and enforces Anthropic signatures on
494
+ * replay; it also rejects the top-level `strict` tool field.
495
+ */
496
+ function isAzureAnthropicRoute(baseUrl) {
497
+ return baseUrl !== void 0 && AZURE_ANTHROPIC_URL_MARKER.test(baseUrl);
498
+ }
499
+ /**
500
+ * Known non-official URLs that enforce Anthropic thinking signatures on replay
501
+ * (GitHub Copilot, ZenMux, Cloudflare AI Gateway `/anthropic`, Google Vertex
502
+ * `publishers/anthropic`, AWS Bedrock, Azure Foundry).
503
+ *
504
+ * Runtime routing calls this with the effective URL because a model's resolved
505
+ * compat can be stale after Foundry or a provider base-URL override reroutes it.
506
+ */
507
+ function isAnthropicSigningProxyUrl(baseUrl) {
508
+ return hostMatchesUrl(baseUrl, "githubCopilot") || hostMatchesUrl(baseUrl, "zenmux") || baseUrl !== void 0 && (CLOUDFLARE_ANTHROPIC_GATEWAY_URL_MARKER.test(baseUrl) || VERTEX_ANTHROPIC_URL_MARKER.test(baseUrl) || BEDROCK_ANTHROPIC_URL_MARKER.test(baseUrl)) || isBedrockAnthropicRoute(baseUrl) || isAzureAnthropicRoute(baseUrl);
509
+ }
510
+ //#endregion
511
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/compat/apply.ts
512
+ /**
513
+ * Assign defined override values onto a freshly-built resolved compat record,
514
+ * in place. Keys the record doesn't declare are ignored (loosely-typed config
515
+ * may carry junk). `buildModel` is the only intended caller — the record being
516
+ * mutated is the single per-model allocation; nothing here runs per request.
517
+ */
518
+ function applyCompatOverrides(compat, overrides) {
519
+ if (!overrides) return;
520
+ for (const key in overrides) {
521
+ const value = overrides[key];
522
+ if (value !== void 0 && key in compat) compat[key] = value;
523
+ }
524
+ }
525
+ //#endregion
526
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/types.ts
527
+ /** Catalog kinds used to isolate role-specific runners from session chat models. */
528
+ const MODEL_KINDS = [
529
+ "chat",
530
+ "tiny",
531
+ "image",
532
+ "tts",
533
+ "stt",
534
+ "search",
535
+ "judge",
536
+ "embedding",
537
+ "rerank",
538
+ "video"
539
+ ];
540
+ /** Kinds a provider maps to a runner transport through `kind-apis` in its KDL; discovery drops rows of these kinds when the provider declares no API. */
541
+ const KIND_API_KINDS = [
542
+ "image",
543
+ "tts",
544
+ "stt",
545
+ "embedding",
546
+ "rerank",
547
+ "video"
548
+ ];
549
+ new Map(Object.entries({
550
+ "web-search": "search",
551
+ typesafe: "judge",
552
+ "openrouter-decisions": "judge",
553
+ "openai-decisions": "judge",
554
+ "workers-ai-systemone": "judge",
555
+ "openai-images": "image",
556
+ "openrouter-images": "image",
557
+ "xai-tts": "tts",
558
+ "openai-speech": "tts",
559
+ "openai-embeddings": "embedding",
560
+ "openrouter-rerank": "rerank",
561
+ "openrouter-video": "video",
562
+ "openai-transcriptions": "stt"
563
+ }));
564
+ //#endregion
565
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/wire/factory-droid.ts
566
+ /**
567
+ * Factory Droid wire constants shared by catalog discovery, the pi-ai
568
+ * provider, OAuth login and account usage: client identity, upstream/region
569
+ * vocabulary, API hosts and the account-scoped model-cache namespace.
570
+ */
571
+ /**
572
+ * Client version reported to Factory's API. When bumping it, recapture the
573
+ * native request corpus with `packages/ai/scripts/capture-factory-droid-native.ts`
574
+ * against the matching CLI binary and make `factory-droid-native-parity.test.ts` pass.
575
+ */
576
+ const FACTORY_DROID_CLIENT_VERSION = "0.237.0";
577
+ /** Wire protocols the Factory proxy multiplexes; `api-routes provider="factory-droid"` picks one per model. */
578
+ const FACTORY_DROID_WIRES = [
579
+ "openai-completions",
580
+ "openai-responses",
581
+ "anthropic-messages",
582
+ "google-generate"
583
+ ];
584
+ /**
585
+ * Upstream routers the proxy dispatches to, sent as the `x-api-provider`
586
+ * header. The KDL compiler validates the rotation and region axes against it.
587
+ */
588
+ const FACTORY_DROID_UPSTREAMS = [
589
+ "fireworks",
590
+ "baseten",
591
+ "mistral",
592
+ "anthropic",
593
+ "azure_anthropic",
594
+ "vertex_anthropic",
595
+ "bedrock_anthropic",
596
+ "openai",
597
+ "azure_openai",
598
+ "bedrock_openai",
599
+ "google",
600
+ "xai",
601
+ "snowflake",
602
+ "databricks"
603
+ ];
604
+ /** Inference region for an account: explicit scope wins, else EU residency infers EU, else global. */
605
+ function resolveFactoryDroidInferenceRegion(scope) {
606
+ return scope.inferenceRegion ?? (scope.region === "eu" ? "eu" : "global");
607
+ }
608
+ /** Factory API host per residency region; EU accounts are served from the EU region. */
609
+ function factoryDroidApiBaseUrl(region) {
610
+ return region === "eu" ? "https://api.eu.factory.ai" : "https://api.factory.ai";
611
+ }
612
+ /** Per-wire base URL for an account region; the stream layer appends the path suffix. */
613
+ function factoryDroidWireBaseUrl(wire, region) {
614
+ const host = factoryDroidApiBaseUrl(region);
615
+ switch (wire) {
616
+ case "openai-completions":
617
+ case "openai-responses": return `${host}/api/llm/o/v1`;
618
+ case "anthropic-messages": return `${host}/api/llm/a`;
619
+ case "google-generate": return `${host}/api/llm/g/v1`;
620
+ }
621
+ }
622
+ /**
623
+ * Client identity headers shared by discovery, usage and inference requests.
624
+ * Callers add their own auth, `Accept`, routing and SDK headers.
625
+ */
626
+ function factoryDroidClientHeaders(orgId) {
627
+ return {
628
+ "X-Client-Version": FACTORY_DROID_CLIENT_VERSION,
629
+ "X-Factory-Client": "cli",
630
+ ...orgId ? { "X-Factory-Org-Id": orgId } : {}
631
+ };
632
+ }
633
+ /** Model-cache namespace for a Factory credential and its account scope. */
634
+ function factoryDroidModelCacheProviderId(options) {
635
+ const token = options.apiKey ?? "";
636
+ let credentialScope = `bearer\u0000${token}`;
637
+ const parts = token.split(".");
638
+ if (parts.length === 3 && parts.every(Boolean)) try {
639
+ const claims = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
640
+ if (isRecord(claims) && !Array.isArray(claims) && typeof claims.external_org_id === "string" && claims.external_org_id.trim() && typeof claims.sub === "string" && claims.sub.trim()) credentialScope = `account\u0000${claims.external_org_id}\u0000${claims.sub}`;
641
+ } catch {}
642
+ const region = options.region === "eu" ? "eu" : "global";
643
+ const scope = `${credentialScope}\u0000${options.orgId ?? ""}\u0000${region}\u0000${options.inferenceRegion ?? region}`;
644
+ return `factory-droid:models-v4:${Bun.hash(scope).toString(36)}`;
645
+ }
646
+ //#endregion
647
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/compat/axes.ts
648
+ const OAI = ["openai", "openai-responses"];
649
+ const EFFORTS = [
650
+ "minimal",
651
+ "low",
652
+ "medium",
653
+ "high",
654
+ "xhigh",
655
+ "max"
656
+ ];
657
+ [...EFFORTS];
658
+ /**
659
+ * How hard agent prompts push subagent delegation for a model lineage
660
+ * (`delegation-bias` axis). `eager` is the unassigned default: the prompt
661
+ * actively pushes fan-out. `restrained` keeps fan-out for genuinely parallel
662
+ * slices but forbids reflexive scouts and single-agent babysitting. `gated`
663
+ * forbids subagents unless the user or a skill asks.
664
+ */
665
+ const DELEGATION_BIASES = [
666
+ "eager",
667
+ "restrained",
668
+ "gated"
669
+ ];
670
+ const THINKING_MODES = [
671
+ "effort",
672
+ "budget",
673
+ "google-level",
674
+ "anthropic-adaptive",
675
+ "anthropic-budget-effort"
676
+ ];
677
+ function wire(key, records, shape = "scalar", values) {
678
+ return {
679
+ key,
680
+ set: "wire",
681
+ shape,
682
+ records,
683
+ values
684
+ };
685
+ }
686
+ /**
687
+ * KDL directive → axis definition. Keys are the kebab-case directive
688
+ * spellings accepted inside `classes/*.kdl` and `providers/*.kdl` rule
689
+ * blocks.
690
+ */
691
+ const AXES = {
692
+ "completions-reasoning-mode": wire("completionsReasoningMode", ["request"], "scalar", [
693
+ "none",
694
+ "effort",
695
+ "opt-in",
696
+ "forced-on"
697
+ ]),
698
+ "completions-reasoning-history": wire("completionsReasoningHistory", ["request"], "scalar", [
699
+ "omit",
700
+ "preserved",
701
+ "interleaved"
702
+ ]),
703
+ "anthropic-thinking": wire("anthropicThinking", ["request"], "scalar", [
704
+ "adaptive",
705
+ "adaptive-summarized",
706
+ "budget-interleaved",
707
+ "budget-effort"
708
+ ]),
709
+ "anthropic-tool-streaming-beta": wire("anthropicToolStreamingBeta", ["request"]),
710
+ "openai-platform-header": wire("openaiPlatformHeader", ["request"]),
711
+ "responses-cache-retention": wire("responsesCacheRetention", ["request"]),
712
+ "responses-verbosity": wire("responsesVerbosity", ["request"], "scalar", ["low"]),
713
+ "responses-service-tier": wire("responsesServiceTier", ["request"], "scalar", ["priority"]),
714
+ "responses-parallel-tool-calls": wire("responsesParallelToolCalls", ["request"]),
715
+ "responses-safety-identifier": wire("responsesSafetyIdentifier", ["request"]),
716
+ "responses-tool-choice-auto": wire("responsesToolChoiceAuto", ["request"]),
717
+ "routing-session-lock": wire("routingSessionLock", ["request"]),
718
+ "google-thinking": wire("googleThinking", ["request"], "scalar", ["level", "level-medium"]),
719
+ "allows-synthetic-reasoning-content-for-tool-calls": wire("allowsSyntheticReasoningContentForToolCalls", OAI),
720
+ "always-send-max-tokens": wire("alwaysSendMaxTokens", OAI),
721
+ "cache-control-format": wire("cacheControlFormat", OAI, "scalar", ["anthropic"]),
722
+ "clamp-output-to-model-max": wire("clampOutputToModelMax", OAI),
723
+ "disable-reasoning-on-forced-tool-choice": wire("disableReasoningOnForcedToolChoice", OAI),
724
+ "disable-reasoning-on-tool-choice": wire("disableReasoningOnToolChoice", OAI),
725
+ "disable-reasoning-with-tools": wire("disableReasoningWithTools", ["openai"]),
726
+ "drop-thinking-when-reasoning-effort": wire("dropThinkingWhenReasoningEffort", ["openai"]),
727
+ "empty-length-finish-is-context-error": wire("emptyLengthFinishIsContextError", OAI),
728
+ "extra-body": {
729
+ ...wire("extraBody", ["openai"], "object"),
730
+ verbatimKeys: true
731
+ },
732
+ "filter-reasoning-history": wire("filterReasoningHistory", OAI),
733
+ "include-encrypted-reasoning": wire("includeEncryptedReasoning", OAI),
734
+ "kimi-api-format": wire("kimiApiFormat", ["openai"], "scalar", ["openai", "anthropic"]),
735
+ "max-tokens-field": wire("maxTokensField", ["openai"], "scalar", ["max_completion_tokens", "max_tokens"]),
736
+ "mistral-reasoning-content-parts": wire("mistralReasoningContentParts", ["openai"]),
737
+ "native-kimi-k3-reasoning": wire("nativeKimiK3Reasoning", ["openai"]),
738
+ "omit-reasoning-effort": wire("omitReasoningEffort", OAI),
739
+ "prompt-cache-breakpoint-ttl": wire("promptCacheBreakpointTtl", OAI, "scalar", ["30m"]),
740
+ "prompt-cache-session-header": wire("promptCacheSessionHeader", OAI, "scalar", ["x-grok-conv-id"]),
741
+ "qwen-preserve-thinking": wire("qwenPreserveThinking", ["openai"]),
742
+ "reject-root-object-union": wire("rejectRootObjectUnion", OAI),
743
+ "retry-without-strict-on-grammar-error": wire("retryWithoutStrictOnGrammarError", OAI),
744
+ "session-header": wire("sessionHeader", OAI, "scalar", ["x-litellm-session-id"]),
745
+ "reasoning-content-field": wire("reasoningContentField", OAI, "scalar", [
746
+ "reasoning_content",
747
+ "reasoning",
748
+ "reasoning_text"
749
+ ]),
750
+ "reasoning-deltas-may-be-cumulative": wire("reasoningDeltasMayBeCumulative", OAI),
751
+ "reasoning-disable-mode": wire("reasoningDisableMode", OAI, "scalar", [
752
+ "omit",
753
+ "lowest-effort",
754
+ "none-effort",
755
+ "openrouter-enabled-false",
756
+ "cline-enabled-false",
757
+ "venice-disable-thinking",
758
+ "zai-thinking-disabled",
759
+ "qwen-enable-thinking-false",
760
+ "qwen-template-false",
761
+ "chat-template-thinking-false"
762
+ ]),
763
+ "reasoning-effort-map": wire("reasoningEffortMap", OAI, "object"),
764
+ "replay-reasoning-content": wire("replayReasoningContent", ["openai"]),
765
+ "synthetic-reasoning-content-fallback": wire("syntheticReasoningContentFallback", ["openai"]),
766
+ "requires-assistant-after-tool-result": wire("requiresAssistantAfterToolResult", ["openai"]),
767
+ "requires-assistant-content-for-tool-calls": wire("requiresAssistantContentForToolCalls", OAI),
768
+ "requires-mistral-tool-ids": wire("requiresMistralToolIds", ["openai"]),
769
+ "requires-reasoning-content-for-all-assistant-turns": wire("requiresReasoningContentForAllAssistantTurns", OAI),
770
+ "requires-reasoning-content-for-tool-calls": wire("requiresReasoningContentForToolCalls", OAI),
771
+ "requires-thinking-as-text": wire("requiresThinkingAsText", ["openai"]),
772
+ "requires-tool-result-name": wire("requiresToolResultName", ["openai"]),
773
+ "strict-responses-pairing": wire("strictResponsesPairing", ["openai-responses"]),
774
+ "connection-bound-native-history": wire("connectionBoundNativeHistory", ["openai-responses"]),
775
+ "stateful-responses": wire("statefulResponses", ["openai-responses"]),
776
+ "requires-reasoning-off-juice-instruction": wire("requiresReasoningOffJuiceInstruction", ["openai-responses"]),
777
+ "supports-all-turns-reasoning-context": wire("supportsAllTurnsReasoningContext", ["openai-responses"]),
778
+ "supports-configuration-update": wire("supportsConfigurationUpdate", ["openai-responses"]),
779
+ "supports-steering": wire("supportsSteering", ["openai-responses"]),
780
+ "strip-deepseek-special-tokens": wire("stripDeepseekSpecialTokens", OAI),
781
+ "stream-markup-healing-pattern": wire("streamMarkupHealingPattern", OAI, "scalar", [
782
+ "kimi",
783
+ "dsml",
784
+ "qwen",
785
+ "thinking",
786
+ "harmony"
787
+ ]),
788
+ "supports-developer-role": wire("supportsDeveloperRole", OAI),
789
+ "supports-image-detail-original": wire("supportsImageDetailOriginal", ["openai-responses"]),
790
+ "supports-long-prompt-cache-retention": wire("supportsLongPromptCacheRetention", [...OAI, "bedrock"]),
791
+ "supports-multiple-system-messages": wire("supportsMultipleSystemMessages", ["openai"]),
792
+ "supports-named-tool-choice": wire("supportsNamedToolChoice", OAI),
793
+ "supports-obfuscation-opt-out": wire("supportsObfuscationOptOut", ["openai-responses"]),
794
+ "harmony-leak-mitigation": wire("harmonyLeakMitigation", ["openai-responses"]),
795
+ "supports-penalty-and-stop-params": wire("supportsPenaltyAndStopParams", OAI),
796
+ "supports-prompt-cache-breakpoints": wire("supportsPromptCacheBreakpoints", OAI),
797
+ "supports-prompt-cache-key": wire("supportsPromptCacheKey", ["openai"]),
798
+ "supports-reasoning-effort": wire("supportsReasoningEffort", OAI),
799
+ "supports-reasoning-params": wire("supportsReasoningParams", OAI),
800
+ "supports-reasoning-summary": wire("supportsReasoningSummary", ["openai-responses"]),
801
+ "store-responses": wire("storeResponses", ["openai-responses"]),
802
+ "supports-store": wire("supportsStore", ["openai"]),
803
+ "supports-strict-mode": wire("supportsStrictMode", OAI),
804
+ "supports-tool-choice": wire("supportsToolChoice", OAI),
805
+ "supports-usage-in-streaming": wire("supportsUsageInStreaming", ["openai"]),
806
+ "template-reasoning-effort": wire("qwenTemplateReasoningEffort", ["openai"]),
807
+ "thinking-format": wire("thinkingFormat", OAI, "scalar", [
808
+ "openai",
809
+ "openrouter",
810
+ "zai",
811
+ "kimi",
812
+ "qwen",
813
+ "qwen-chat-template",
814
+ "chat-template"
815
+ ]),
816
+ "thinking-keep": wire("thinkingKeep", ["openai"]),
817
+ "tool-schema-flavor": wire("toolSchemaFlavor", OAI, "scalar", [
818
+ "moonshot-mfjs",
819
+ "grammar",
820
+ "none"
821
+ ]),
822
+ "tool-strict-mode": wire("toolStrictMode", ["openai"], "scalar", [
823
+ "all_strict",
824
+ "none",
825
+ "mixed"
826
+ ]),
827
+ "uses-openai-tool-call-id-limit": wire("usesOpenAIToolCallIdLimit", OAI),
828
+ "when-thinking": wire("whenThinking", ["openai"], "object"),
829
+ "wire-model-id-mode": wire("wireModelIdMode", OAI, "scalar", [
830
+ "raw",
831
+ "cline-pass",
832
+ "firepass",
833
+ "fireworks",
834
+ "openrouter"
835
+ ]),
836
+ "zai-reasoning-effort-dialect": wire("zaiReasoningEffortDialect", ["openai"]),
837
+ "bedrock-messages-api": wire("bedrockMessagesApi", ["anthropic"]),
838
+ "allow-anthropic-header-overrides": wire("allowAnthropicHeaderOverrides", ["anthropic"]),
839
+ "disable-adaptive-thinking": wire("disableAdaptiveThinking", ["anthropic"]),
840
+ "disable-strict-tools": wire("disableStrictTools", ["anthropic"]),
841
+ "between-tools-effort": wire("betweenToolsEffort", ["anthropic"], "scalar", [
842
+ "low",
843
+ "medium",
844
+ "high"
845
+ ]),
846
+ "disabled-thinking": wire("disabledThinking", ["anthropic", "bedrock"], "scalar", [
847
+ "omit",
848
+ "disabled",
849
+ "adaptive",
850
+ "between-tools"
851
+ ]),
852
+ "effort-beta": wire("effortBeta", ["anthropic"]),
853
+ "escape-builtin-tool-names": wire("escapeBuiltinToolNames", ["anthropic"]),
854
+ "fast-mode": wire("fastMode", ["anthropic"]),
855
+ "first-party-provider": wire("firstPartyProvider", ["anthropic"]),
856
+ "honors-claude-code-beta-kill-switch": wire("honorsClaudeCodeBetaKillSwitch", ["anthropic"]),
857
+ "inject-claude-code-instruction": wire("injectClaudeCodeInstruction", ["anthropic"]),
858
+ "max-image-dimension": wire("maxImageDimension", ["anthropic", "google"]),
859
+ "max-image-payload-bytes": wire("maxImagePayloadBytes", ["anthropic", "google"]),
860
+ "official-endpoint": wire("officialEndpoint", ["anthropic", "openai-responses"]),
861
+ "replay-unsigned-thinking": wire("replayUnsignedThinking", ["anthropic"]),
862
+ "requires-thinking-enabled": wire("requiresThinkingEnabled", ["anthropic"]),
863
+ "requires-tool-result-id": wire("requiresToolResultId", ["anthropic"]),
864
+ "signing-endpoint": wire("signingEndpoint", ["anthropic"]),
865
+ "strip-thinking-history": wire("stripThinkingHistory", [
866
+ "openai",
867
+ "anthropic",
868
+ "ollama"
869
+ ]),
870
+ "supports-context-management": wire("supportsContextManagement", ["anthropic"]),
871
+ "supports-output-effort": wire("supportsOutputEffort", ["anthropic"]),
872
+ "supports-eager-tool-input-streaming": wire("supportsEagerToolInputStreaming", ["anthropic"]),
873
+ "supports-long-cache-retention": wire("supportsLongCacheRetention", ["anthropic"]),
874
+ "supports-mid-conversation-system": wire("supportsMidConversationSystem", ["anthropic"]),
875
+ "supports-mid-conversation-tool-changes": wire("supportsMidConversationToolChanges", ["anthropic"]),
876
+ "supports-per-message-effort": wire("supportsPerMessageEffort", ["anthropic"]),
877
+ "supports-server-compaction": wire("supportsServerCompaction", ["anthropic", "bedrock"]),
878
+ "supports-between-tools-thinking": wire("supportsBetweenToolsThinking", ["anthropic"]),
879
+ "supports-thinking-binding-controls": wire("supportsThinkingBindingControls", ["anthropic", "bedrock"]),
880
+ "supports-turn-scoped-system": wire("supportsTurnScopedSystem", ["anthropic"]),
881
+ "prompt-cache-maximum-checkpoints": wire("promptCacheMaximumCheckpoints", ["bedrock"]),
882
+ "prompt-cache-minimum-tokens": wire("promptCacheMinimumTokens", ["bedrock"]),
883
+ "prompt-cache-mode": wire("promptCacheMode", ["bedrock"], "scalar", [
884
+ "none",
885
+ "automatic",
886
+ "explicit"
887
+ ]),
888
+ "model-router": wire("modelRouter", ["devin"]),
889
+ "supports-parallel-tool-calls": wire("supportsParallelToolCalls", ["devin"]),
890
+ "trust-explicit-thinking-only": wire("trustExplicitThinkingOnly", [...OAI, "devin"]),
891
+ "antigravity-claude-tool-mode": wire("antigravityClaudeToolMode", ["google"]),
892
+ "antigravity-usage-label": wire("antigravityUsageLabel", ["google"]),
893
+ "cca-legacy-parameters-schema": wire("ccaLegacyParametersSchema", ["google"]),
894
+ "claude-thinking-beta-header": wire("claudeThinkingBetaHeader", ["google"]),
895
+ "drop-unsigned-thinking": wire("dropUnsignedThinking", ["google"]),
896
+ "flash-stream-leak-workaround": wire("flashStreamLeakWorkaround", ["google"]),
897
+ "multimodal-function-response": wire("multimodalFunctionResponse", ["google"]),
898
+ "requires-skip-thought-signature": wire("requiresSkipThoughtSignature", ["google"]),
899
+ "requires-skip-thought-signature-on-first-function-call": wire("requiresSkipThoughtSignatureOnFirstFunctionCall", ["google"]),
900
+ "supports-function-part-id": wire("supportsFunctionPartId", ["google"]),
901
+ /**
902
+ * Whether this wire may revise text it has already streamed: bytes
903
+ * reclassified out of the visible channel (a leaned-on thinking opener),
904
+ * carved into a tool call, reordered by content-block index, or replaced
905
+ * wholesale by an authoritative final payload. Unassigned means the wire
906
+ * only appends, so the transcript may retire finished lines into native
907
+ * scrollback while the turn is still streaming (see
908
+ * `AssistantMessageComponent`). Declare `possible` only with a citable
909
+ * mechanism: the renderer also verifies published rows every frame and stops
910
+ * retiring the block on the first mismatch, so this axis decides where
911
+ * mid-stream retirement is attempted, not whether it is safe.
912
+ */
913
+ "stream-revision": wire("streamRevision", [...OAI, "bedrock"], "scalar", ["none", "possible"]),
914
+ "stream-first-event-timeout-ms": wire("streamFirstEventTimeoutMs", [...OAI, "google"]),
915
+ "stream-idle-timeout-ms": wire("streamIdleTimeoutMs", [
916
+ ...OAI,
917
+ "anthropic",
918
+ "bedrock",
919
+ "google"
920
+ ]),
921
+ "strip-image-input": wire("stripImageInput", [
922
+ ...OAI,
923
+ "anthropic",
924
+ "google"
925
+ ]),
926
+ "supports-forced-tool-choice": wire("supportsForcedToolChoice", [
927
+ ...OAI,
928
+ "anthropic",
929
+ "bedrock"
930
+ ]),
931
+ "supports-sampling-params": wire("supportsSamplingParams", [
932
+ ...OAI,
933
+ "anthropic",
934
+ "bedrock",
935
+ "devin",
936
+ "google"
937
+ ]),
938
+ "thinking-loop-guard": wire("thinkingLoopGuard", [
939
+ ...OAI,
940
+ "anthropic",
941
+ "google"
942
+ ], "scalar", [
943
+ "gemini",
944
+ "deepseek",
945
+ "xai"
946
+ ]),
947
+ "thinking-default-level": {
948
+ key: "defaultLevel",
949
+ set: "thinking",
950
+ shape: "scalar",
951
+ values: EFFORTS
952
+ },
953
+ "thinking-effort-budgets": {
954
+ key: "effortBudgets",
955
+ set: "thinking",
956
+ shape: "object"
957
+ },
958
+ "thinking-effort-map": {
959
+ key: "effortMap",
960
+ set: "thinking",
961
+ shape: "object"
962
+ },
963
+ "thinking-efforts": {
964
+ key: "efforts",
965
+ set: "thinking",
966
+ shape: "array",
967
+ values: EFFORTS,
968
+ emptyArray: true
969
+ },
970
+ "thinking-mode": {
971
+ key: "mode",
972
+ set: "thinking",
973
+ shape: "scalar",
974
+ values: THINKING_MODES
975
+ },
976
+ "thinking-requires-effort": {
977
+ key: "requiresEffort",
978
+ set: "thinking",
979
+ shape: "scalar"
980
+ },
981
+ "thinking-prefix-binding": {
982
+ key: "prefixBinding",
983
+ set: "thinking",
984
+ shape: "scalar"
985
+ },
986
+ "thinking-suppress-when-off": {
987
+ key: "suppressWhenOff",
988
+ set: "thinking",
989
+ shape: "scalar"
990
+ },
991
+ "thinking-supports-display": {
992
+ key: "supportsDisplay",
993
+ set: "thinking",
994
+ shape: "scalar"
995
+ },
996
+ "thinking-upgrade-neutral": {
997
+ key: "upgradeNeutral",
998
+ set: "thinking",
999
+ shape: "scalar"
1000
+ },
1001
+ /** Unclassified neutral ids here are capability-unknown: offer the ladder as opt-in. */
1002
+ "thinking-unverified": {
1003
+ key: "unverified",
1004
+ set: "thinking",
1005
+ shape: "scalar"
1006
+ },
1007
+ "apply-patch-tool-type": {
1008
+ key: "applyPatchToolType",
1009
+ set: "catalog",
1010
+ shape: "scalar",
1011
+ values: ["freeform", "function"]
1012
+ },
1013
+ "requires-native-tools": {
1014
+ key: "requiresNativeTools",
1015
+ set: "catalog",
1016
+ shape: "scalar",
1017
+ values: [true, false]
1018
+ },
1019
+ "tool-schemas-in-context": {
1020
+ key: "toolSchemasInContext",
1021
+ set: "catalog",
1022
+ shape: "scalar",
1023
+ values: [true, false]
1024
+ },
1025
+ "requires-tool-free-history-for-tool-opt-out": {
1026
+ key: "requiresToolFreeHistoryForToolOptOut",
1027
+ set: "catalog",
1028
+ shape: "scalar",
1029
+ values: [true, false]
1030
+ },
1031
+ /** Replayed tool calls must satisfy the target wire's declaration charset and length. */
1032
+ "tool-call-name-charset": {
1033
+ key: "toolCallNameCharset",
1034
+ set: "catalog",
1035
+ shape: "scalar",
1036
+ values: ["ascii", "google"]
1037
+ },
1038
+ "tool-call-name-max-length": {
1039
+ key: "toolCallNameMaxLength",
1040
+ set: "catalog",
1041
+ shape: "scalar"
1042
+ },
1043
+ "preserves-max-output-tokens": {
1044
+ key: "preservesMaxOutputTokens",
1045
+ set: "catalog",
1046
+ shape: "scalar",
1047
+ values: [true, false]
1048
+ },
1049
+ "omit-max-output-tokens": {
1050
+ key: "omitMaxOutputTokens",
1051
+ set: "catalog",
1052
+ shape: "scalar",
1053
+ values: [true, false]
1054
+ },
1055
+ /**
1056
+ * The host accepts a prompt plus `max_tokens` beyond the context window and
1057
+ * ends generation at the window (Anthropic `model_context_window_exceeded`)
1058
+ * instead of rejecting the request, so callers must not lower the output cap
1059
+ * to fit the window.
1060
+ */
1061
+ "stops-output-at-context-window": {
1062
+ key: "stopsOutputAtContextWindow",
1063
+ set: "catalog",
1064
+ shape: "scalar",
1065
+ values: [true, false]
1066
+ },
1067
+ /**
1068
+ * The model's input classifier refuses requests that reproduce assistant
1069
+ * reasoning as quoted text (`reasoning_extraction`), so reasoning must not
1070
+ * be replayed as text into its input: compaction archives, summarizer
1071
+ * transcripts and demoted interrupted turns leave it out. Declared per class
1072
+ * in `classes/*.kdl`.
1073
+ */
1074
+ "classifier-cot-extraction": {
1075
+ key: "classifierCotExtraction",
1076
+ set: "catalog",
1077
+ shape: "scalar",
1078
+ values: [true, false]
1079
+ },
1080
+ "clamp-context-override": {
1081
+ key: "clampContextOverride",
1082
+ set: "catalog",
1083
+ shape: "scalar"
1084
+ },
1085
+ "context-promotion-target": {
1086
+ key: "contextPromotionTarget",
1087
+ set: "catalog",
1088
+ shape: "scalar"
1089
+ },
1090
+ "context-window-floor": {
1091
+ key: "contextWindowFloor",
1092
+ set: "catalog",
1093
+ shape: "scalar"
1094
+ },
1095
+ "context-window-authoritative": {
1096
+ key: "contextWindowAuthoritative",
1097
+ set: "catalog",
1098
+ shape: "scalar",
1099
+ values: [true, false]
1100
+ },
1101
+ /**
1102
+ * The model's long-context price tier does not bound its runtime context
1103
+ * window: with extended context off, the window is not capped at the
1104
+ * tier's input threshold (subscription hosts carrying API-equivalent tier
1105
+ * prices, or a model served at its full window). Explicit user context
1106
+ * overrides still apply.
1107
+ */
1108
+ "long-context-window-uncapped": {
1109
+ key: "longContextWindowUncapped",
1110
+ set: "catalog",
1111
+ shape: "scalar",
1112
+ values: [true, false]
1113
+ },
1114
+ "cost-patch": {
1115
+ key: "costPatch",
1116
+ set: "catalog",
1117
+ shape: "object"
1118
+ },
1119
+ "cost-fallback": {
1120
+ key: "costFallback",
1121
+ set: "catalog",
1122
+ shape: "object"
1123
+ },
1124
+ /**
1125
+ * The host bills cache-hit input tokens at the full input rate (no cache
1126
+ * discount), so the built row's `cacheRead` tracks its live `input` price.
1127
+ */
1128
+ "cache-read-at-input-rate": {
1129
+ key: "cacheReadAtInputRate",
1130
+ set: "catalog",
1131
+ shape: "scalar",
1132
+ values: [true, false]
1133
+ },
1134
+ /**
1135
+ * The host bills cache writes at this multiple of the row's live `input`
1136
+ * price, for hosts whose discovery reports cache-write tokens but no
1137
+ * cache-write rate. It replaces any `cacheWrite` the row carries, including
1138
+ * a `cost-patch`/`cost-fallback` value and an absolute long-context tier's
1139
+ * `cacheWrite` (rebased on the tier's `input`).
1140
+ */
1141
+ "cache-write-rate": {
1142
+ key: "cacheWriteRate",
1143
+ set: "catalog",
1144
+ shape: "scalar"
1145
+ },
1146
+ /**
1147
+ * How the model line bills a replayed signed thinking block as input:
1148
+ * `output` bills the reasoning its signature carries, at the size the turn
1149
+ * billed as output, and not the signature's bytes. Unassigned: estimated
1150
+ * from the signature's bytes. Read through `./thinking-replay`.
1151
+ */
1152
+ "thinking-replay-tokens": {
1153
+ key: "thinkingReplayTokens",
1154
+ set: "catalog",
1155
+ shape: "scalar",
1156
+ values: ["output", "signature"]
1157
+ },
1158
+ "delegation-bias": {
1159
+ key: "delegationBias",
1160
+ set: "catalog",
1161
+ shape: "scalar",
1162
+ values: DELEGATION_BIASES
1163
+ },
1164
+ "discovery-api": {
1165
+ key: "discoveryApi",
1166
+ set: "catalog",
1167
+ shape: "scalar"
1168
+ },
1169
+ "edit-prompt-variant": {
1170
+ key: "editPromptVariant",
1171
+ set: "catalog",
1172
+ shape: "scalar",
1173
+ values: ["full", "compact"]
1174
+ },
1175
+ "edit-revision": {
1176
+ key: "editRevision",
1177
+ set: "catalog",
1178
+ shape: "scalar"
1179
+ },
1180
+ "input-modalities": {
1181
+ key: "inputModalities",
1182
+ set: "catalog",
1183
+ shape: "array",
1184
+ values: ["text", "image"]
1185
+ },
1186
+ kind: {
1187
+ key: "kind",
1188
+ set: "catalog",
1189
+ shape: "scalar",
1190
+ values: MODEL_KINDS
1191
+ },
1192
+ "web-search": {
1193
+ key: "webSearch",
1194
+ set: "catalog",
1195
+ shape: "scalar",
1196
+ values: [
1197
+ "gemini",
1198
+ "anthropic",
1199
+ "codex",
1200
+ "xai",
1201
+ "openrouter",
1202
+ "openai"
1203
+ ]
1204
+ },
1205
+ "web-search-model": {
1206
+ key: "webSearchModel",
1207
+ set: "catalog",
1208
+ shape: "scalar"
1209
+ },
1210
+ "hosted-image": {
1211
+ key: "hostedImage",
1212
+ set: "catalog",
1213
+ shape: "scalar",
1214
+ values: [true, false]
1215
+ },
1216
+ /** How the model line bills an input image; shape and formulas in `./image-tokenization`. */
1217
+ "image-tokenization": {
1218
+ key: "imageTokenization",
1219
+ set: "catalog",
1220
+ shape: "object"
1221
+ },
1222
+ /**
1223
+ * Most images one request may carry, documents included where the host
1224
+ * counts them. Unassigned: unknown host, held to a conservative floor.
1225
+ */
1226
+ "image-count-budget": {
1227
+ key: "imageCountBudget",
1228
+ set: "catalog",
1229
+ shape: "scalar"
1230
+ },
1231
+ /**
1232
+ * Replaces `image-count-budget` while the request reaches the official
1233
+ * endpoint (pi-ai `reachesBudgetedHost`): a limit measured or documented
1234
+ * for the host's own endpoint, which a custom `baseUrl` or an
1235
+ * `ANTHROPIC_BASE_URL`/`FOUNDRY_BASE_URL` reroute (proxy, gateway) need not share.
1236
+ */
1237
+ "official-image-count-budget": {
1238
+ key: "officialImageCountBudget",
1239
+ set: "catalog",
1240
+ shape: "scalar"
1241
+ },
1242
+ /**
1243
+ * Opt-in: the reader may get a fresh `read` result as snapcompact frames
1244
+ * (`snapcompact.toolResults`), because it edits as exactly from frames as
1245
+ * from text. Unassigned: `read` results stay text, since a reader that
1246
+ * misreads indentation in frames makes inexact edits.
1247
+ */
1248
+ "snapcompact-image-reads": {
1249
+ key: "snapcompactImageReads",
1250
+ set: "catalog",
1251
+ shape: "scalar",
1252
+ values: [true, false]
1253
+ },
1254
+ "image-model": {
1255
+ key: "imageModel",
1256
+ set: "catalog",
1257
+ shape: "scalar"
1258
+ },
1259
+ /** Longest image edge the host passes to the model: it downscales larger images to fit first. */
1260
+ "image-max-edge": {
1261
+ key: "imageMaxEdge",
1262
+ set: "catalog",
1263
+ shape: "scalar"
1264
+ },
1265
+ "inline-image-byte-budget": {
1266
+ key: "inlineImageByteBudget",
1267
+ set: "catalog",
1268
+ shape: "scalar"
1269
+ },
1270
+ /**
1271
+ * Largest request body the host accepts. Where set, the inline-image byte clamp keeps the newest user message's
1272
+ * and newest tool result's images past `inline-image-byte-budget` while they alone fit this limit.
1273
+ */
1274
+ "request-body-byte-limit": {
1275
+ key: "requestBodyByteLimit",
1276
+ set: "catalog",
1277
+ shape: "scalar"
1278
+ },
1279
+ /**
1280
+ * Opt-in: the host budgets above apply whenever the request reaches the provider's own catalog endpoint
1281
+ * (`endpoint-hosts`, or an unset `baseUrl`), for a hosted gateway whose compat names no official endpoint.
1282
+ * Unassigned: they apply only on the official endpoint (pi-ai `reachesOfficialEndpoint`).
1283
+ */
1284
+ "catalog-endpoint-budgets": {
1285
+ key: "catalogEndpointBudgets",
1286
+ set: "catalog",
1287
+ shape: "scalar",
1288
+ values: [true, false]
1289
+ },
1290
+ /**
1291
+ * Supported formats and size bounds for judgment-request images; `mime-types`
1292
+ * is comma-separated because object payloads have no array shape.
1293
+ */
1294
+ "judgment-image-input": {
1295
+ key: "judgmentImageInput",
1296
+ set: "catalog",
1297
+ shape: "object"
1298
+ },
1299
+ /**
1300
+ * `Content-Encoding`s the host decodes on request bodies, most preferred
1301
+ * first. Applied only while the request reaches the provider's own endpoint
1302
+ * (see `endpoint-hosts`), so a proxy or rerouted endpoint never receives
1303
+ * bytes it cannot read. Unassigned: bodies are sent uncompressed.
1304
+ */
1305
+ "request-encodings": {
1306
+ key: "requestEncodings",
1307
+ set: "catalog",
1308
+ shape: "array",
1309
+ values: ["zstd", "gzip"]
1310
+ },
1311
+ /**
1312
+ * HTTPS hostnames the provider itself serves besides its bundled base URL's
1313
+ * host — per-account endpoints such as Copilot's plan hosts. Together with
1314
+ * that host they define the provider's own endpoint, which tells first-party
1315
+ * traffic from a custom gateway that reuses the provider id.
1316
+ */
1317
+ "endpoint-hosts": {
1318
+ key: "endpointHosts",
1319
+ set: "catalog",
1320
+ shape: "array"
1321
+ },
1322
+ /**
1323
+ * Pattern of the JSON 400/415 error body the host returns when it cannot
1324
+ * decode a compressed request body. Unassigned: every JSON 400/415 is a
1325
+ * possible rejection and is re-checked with an uncompressed resend. Either
1326
+ * way, a 400/403/415 whose body is not JSON (presumed a proxy's answer, not
1327
+ * the host's) is re-checked too.
1328
+ */
1329
+ "request-encoding-rejection": {
1330
+ key: "requestEncodingRejection",
1331
+ set: "catalog",
1332
+ shape: "scalar"
1333
+ },
1334
+ /**
1335
+ * Most questions one System One judgment request may carry; the judge
1336
+ * splits larger requests. Unassigned: the endpoint takes any batch size.
1337
+ */
1338
+ "judgment-questions-max": {
1339
+ key: "judgmentQuestionsMax",
1340
+ set: "catalog",
1341
+ shape: "scalar"
1342
+ },
1343
+ "limits-patch": {
1344
+ key: "limitsPatch",
1345
+ set: "catalog",
1346
+ shape: "object"
1347
+ },
1348
+ /** Seeds `maxTokens` only when the row reports none; applied after `limits-patch`. */
1349
+ "max-tokens-fallback": {
1350
+ key: "maxTokensFallback",
1351
+ set: "catalog",
1352
+ shape: "scalar"
1353
+ },
1354
+ /** Most output tokens the host serves: a larger reported `maxTokens` is lowered to it; an unknown one stays unknown. */
1355
+ "max-tokens-ceiling": {
1356
+ key: "maxTokensCeiling",
1357
+ set: "catalog",
1358
+ shape: "scalar"
1359
+ },
1360
+ "long-context-cost": {
1361
+ key: "longContext",
1362
+ set: "catalog",
1363
+ shape: "object"
1364
+ },
1365
+ "prompt-cache": {
1366
+ key: "promptCache",
1367
+ set: "catalog",
1368
+ shape: "object"
1369
+ },
1370
+ "task-sibling-prompt-cache": {
1371
+ key: "taskSiblingPromptCache",
1372
+ set: "catalog",
1373
+ shape: "scalar",
1374
+ values: [true, false]
1375
+ },
1376
+ /**
1377
+ * Prompt-cache lookback in block positions: how far back from a cache
1378
+ * breakpoint the provider looks for an earlier request's cache entry.
1379
+ * Unassigned: no known lookback bound.
1380
+ */
1381
+ "prompt-cache-lookback": {
1382
+ key: "promptCacheLookback",
1383
+ set: "catalog",
1384
+ shape: "scalar"
1385
+ },
1386
+ /**
1387
+ * The provider's own endpoint keeps prompt-cache entries indefinitely
1388
+ * (logged-in Codex subscriptions): an idle gap never cools the prefix, so
1389
+ * rewriting it while idle only discards a warm cache. Read through
1390
+ * `compat/prompt-cache-persistent.ts`. Unassigned: entries expire.
1391
+ */
1392
+ "prompt-cache-persistent": {
1393
+ key: "promptCachePersistent",
1394
+ set: "catalog",
1395
+ shape: "scalar",
1396
+ values: [true, false]
1397
+ },
1398
+ "long-usage-limit-fallback": {
1399
+ key: "longUsageLimitFallback",
1400
+ set: "catalog",
1401
+ shape: "scalar"
1402
+ },
1403
+ "max-context-window": {
1404
+ key: "maxContextWindow",
1405
+ set: "catalog",
1406
+ shape: "scalar"
1407
+ },
1408
+ /**
1409
+ * Every host of the model returns its full plaintext trace wherever the
1410
+ * wire does not mark reasoning as a summary (`ThinkingContent.summary ===
1411
+ * false` vouches for nothing more), and its identity (class + family +
1412
+ * revision) pins one set of weights, so a turn's reasoning may replay
1413
+ * natively on another host serving the same model. Marked summaries never
1414
+ * carry; do not declare it where a host serves summaries unmarked.
1415
+ * Declared per family in `classes/*.kdl`; a host whose reasoning must not be
1416
+ * carried in or out sets `#false` in its `providers/*.kdl`. Read through
1417
+ * `compat/reasoning-carry.ts`.
1418
+ */
1419
+ "portable-reasoning": {
1420
+ key: "portableReasoning",
1421
+ set: "catalog",
1422
+ shape: "scalar",
1423
+ values: [true, false]
1424
+ },
1425
+ "pricing-status": {
1426
+ key: "pricingStatus",
1427
+ set: "catalog",
1428
+ shape: "scalar",
1429
+ values: [
1430
+ "free",
1431
+ "included",
1432
+ "variable",
1433
+ "unknown"
1434
+ ]
1435
+ },
1436
+ "requires-cursor-tool-schema-projection": {
1437
+ key: "requiresCursorToolSchemaProjection",
1438
+ set: "catalog",
1439
+ shape: "scalar"
1440
+ },
1441
+ "requires-tool-result-image-hoisting": {
1442
+ key: "requiresToolResultImageHoisting",
1443
+ set: "catalog",
1444
+ shape: "scalar"
1445
+ },
1446
+ "supports-assistant-prefill": {
1447
+ key: "supportsAssistantPrefill",
1448
+ set: "catalog",
1449
+ shape: "scalar"
1450
+ },
1451
+ /**
1452
+ * Ordered Anthropic model ids forwarded as the server-side `fallbacks`
1453
+ * chain when the user opts in. Each must appear in the requested model's
1454
+ * `allowed_fallback_models` (GET /v1/models/{id}); anything else is a 400.
1455
+ */
1456
+ "server-side-fallback-models": {
1457
+ key: "serverSideFallbackModels",
1458
+ set: "catalog",
1459
+ shape: "array"
1460
+ },
1461
+ /**
1462
+ * Anthropic model ids a refusal's `fallback_credit_token` may be redeemed
1463
+ * on (the refused model's permitted fallback targets). Unordered; a retry
1464
+ * on any other model cannot redeem the credit.
1465
+ */
1466
+ "fallback-credit-targets": {
1467
+ key: "fallbackCreditTargets",
1468
+ set: "catalog",
1469
+ shape: "array"
1470
+ },
1471
+ priority: {
1472
+ key: "priority",
1473
+ set: "catalog",
1474
+ shape: "scalar"
1475
+ },
1476
+ "service-tier-cost": {
1477
+ key: "serviceTierCost",
1478
+ set: "catalog",
1479
+ shape: "object"
1480
+ },
1481
+ "time-based-cost": {
1482
+ key: "timeBased",
1483
+ set: "catalog",
1484
+ shape: "object"
1485
+ },
1486
+ /** Ordered upstream rotation; the first entry is the default `x-api-provider`. */
1487
+ "upstream-rotation": {
1488
+ key: "upstreamRotation",
1489
+ set: "catalog",
1490
+ shape: "array",
1491
+ values: FACTORY_DROID_UPSTREAMS
1492
+ },
1493
+ /**
1494
+ * Upstreams eligible to serve one inference region. The provider-wide rule
1495
+ * is the upstream serving table; a model rule replaces it (the native
1496
+ * region override), and a bare directive means the region never serves it.
1497
+ */
1498
+ "region-upstreams-global": {
1499
+ key: "regionUpstreamsGlobal",
1500
+ set: "catalog",
1501
+ shape: "array",
1502
+ values: FACTORY_DROID_UPSTREAMS,
1503
+ emptyArray: true
1504
+ },
1505
+ "region-upstreams-us": {
1506
+ key: "regionUpstreamsUs",
1507
+ set: "catalog",
1508
+ shape: "array",
1509
+ values: FACTORY_DROID_UPSTREAMS,
1510
+ emptyArray: true
1511
+ },
1512
+ "region-upstreams-eu": {
1513
+ key: "regionUpstreamsEu",
1514
+ set: "catalog",
1515
+ shape: "array",
1516
+ values: FACTORY_DROID_UPSTREAMS,
1517
+ emptyArray: true
1518
+ },
1519
+ /** EU inference limits (`context-window`, `max-tokens`) where the region narrows the default. */
1520
+ "region-limits-eu": {
1521
+ key: "regionLimitsEu",
1522
+ set: "catalog",
1523
+ shape: "object"
1524
+ },
1525
+ /**
1526
+ * Subscription credit rates: `input` is the per-token credit weight shown
1527
+ * as the model's multiplier; `output` and `cache-read` multiply it.
1528
+ */
1529
+ "credit-rates": {
1530
+ key: "creditRates",
1531
+ set: "catalog",
1532
+ shape: "object"
1533
+ },
1534
+ /**
1535
+ * List price borrowed from a bundled catalog row: provider id, then the
1536
+ * row id when it differs from the model's own. Absent means no list price.
1537
+ */
1538
+ "list-price-from": {
1539
+ key: "listPriceFrom",
1540
+ set: "catalog",
1541
+ shape: "array"
1542
+ },
1543
+ /** Provider family whose live routing defaults apply to the model. */
1544
+ "routing-family": {
1545
+ key: "routingFamily",
1546
+ set: "catalog",
1547
+ shape: "scalar",
1548
+ values: [
1549
+ "anthropic",
1550
+ "openai",
1551
+ "google",
1552
+ "factory",
1553
+ "xai"
1554
+ ]
1555
+ },
1556
+ /** Other ids organization policy may use for the model. */
1557
+ "policy-aliases": {
1558
+ key: "policyAliases",
1559
+ set: "catalog",
1560
+ shape: "array"
1561
+ },
1562
+ /**
1563
+ * Account gates: `feature-flag` must be on to list the model,
1564
+ * `deprecation-flag` hides it once on, `requires-explicit-opt-in` hides it
1565
+ * without an org policy, and `base-variant` marks a fast tier of that model.
1566
+ */
1567
+ entitlement: {
1568
+ key: "entitlement",
1569
+ set: "catalog",
1570
+ shape: "object"
1571
+ },
1572
+ /** The native default when the caller picks no effort is thinking off. */
1573
+ "default-reasoning-off": {
1574
+ key: "defaultReasoningOff",
1575
+ set: "catalog",
1576
+ shape: "scalar",
1577
+ values: [true, false]
1578
+ }
1579
+ };
1580
+ /** Records applicable to each API family; used by `resolve.ts` when applying wire axes. */
1581
+ const API_COMPAT_RECORDS = {
1582
+ "ollama-chat": ["ollama"],
1583
+ "openai-completions": ["openai"],
1584
+ openrouter: ["openai", "openai-responses"],
1585
+ "openai-responses": ["openai-responses"],
1586
+ "azure-openai-responses": ["openai-responses"],
1587
+ "openai-codex-responses": ["openai-responses"],
1588
+ "anthropic-messages": ["anthropic"],
1589
+ "bedrock-converse-stream": ["bedrock"],
1590
+ "devin-agent": ["devin"],
1591
+ "google-generative-ai": ["google"],
1592
+ "google-vertex": ["google"],
1593
+ "google-gemini-cli": ["google"]
1594
+ };
1595
+ //#endregion
1596
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/compat/resolve.ts
1597
+ /**
1598
+ * `resolveModelPolicy` — the single model-policy resolver. Layering, later
1599
+ * layers win:
1600
+ *
1601
+ * 1. unconditional per-API compat defaults;
1602
+ * 2. host-derived flags: URL/provider detection via `hosts.ts`, including
1603
+ * compound host×identity branches (keyed on {@link ModelIdentity} fields,
1604
+ * never on model-name matching);
1605
+ * 3. compat-cascade axes compiled from `rules/` (pure identity- and
1606
+ * provider-keyed policy lives there, not here);
1607
+ * 4. spec-authored sparse overrides (`applyCompatOverrides`), then the
1608
+ * spec-undefined fixups the legacy builders applied.
1609
+ *
1610
+ * Thinking metadata resolves after compat: explicit spec thinking wins,
1611
+ * cascade thinking axes drive the ladder/mode/wire facts, and identity-generic
1612
+ * fallbacks cover unmatched targets.
1613
+ */
1614
+ const REQUEST_AXIS_KEYS = Object.values(AXES).filter((axis) => axis.records?.includes("request")).map((axis) => axis.key);
1615
+ function resolveRequestPolicy(axes) {
1616
+ const policy = {};
1617
+ for (const key of REQUEST_AXIS_KEYS) if (key in axes.wire) policy[key] = axes.wire[key];
1618
+ return policy;
1619
+ }
1620
+ /** Structured identity plus revision comparison helpers. */
1621
+ var IdentityFacts = class {
1622
+ identity;
1623
+ revision;
1624
+ constructor(identity) {
1625
+ this.identity = identity;
1626
+ this.revision = identity.revision === void 0 ? void 0 : parseRevision(identity.revision);
1627
+ }
1628
+ is(cls) {
1629
+ return this.identity.class === cls;
1630
+ }
1631
+ family(...families) {
1632
+ return this.identity.family !== void 0 && families.includes(this.identity.family);
1633
+ }
1634
+ revGte(min) {
1635
+ if (!this.revision) return false;
1636
+ const bound = parseRevision(min);
1637
+ return bound !== void 0 && compareRevision(this.revision, bound) >= 0;
1638
+ }
1639
+ revMajor() {
1640
+ return this.revision?.[0];
1641
+ }
1642
+ /** Kimi K2.7-Code / K3 lines whose native hosts mandate enabled thinking. */
1643
+ get kimiMandatoryThinking() {
1644
+ return this.is("kimi") && this.family("k2.7-code", "k3");
1645
+ }
1646
+ /** Adaptive-thinking Claude generation floor (Opus ≥ min; Sonnet/Fable/Mythos ≥ 5; Haiku ≥ 5.5). */
1647
+ anthropicAdaptiveGenAtLeast(opusMin) {
1648
+ if (!this.is("anthropic")) return false;
1649
+ if (this.family("opus")) return this.revGte(opusMin);
1650
+ if (this.family("sonnet", "fable", "mythos")) return this.revGte("5");
1651
+ if (this.family("haiku")) return this.revGte("5.5");
1652
+ return false;
1653
+ }
1654
+ };
1655
+ /**
1656
+ * The id a spec resolves identity and rules under: its own, unless that names
1657
+ * no model and the row sends a model that does on the wire. A Devin Fusion
1658
+ * pairing runs only its lead, so the lead's reviewed rules (cache-write rate,
1659
+ * long-context tier) apply to it at build time.
1660
+ */
1661
+ function policyModelId(spec) {
1662
+ const wireId = spec.requestModelId;
1663
+ if (wireId === void 0 || wireId === spec.id) return spec.id;
1664
+ if (classifyModel(spec.provider, spec.id).class !== "unknown") return spec.id;
1665
+ return classifyModel(spec.provider, wireId).class === "unknown" ? spec.id : wireId;
1666
+ }
1667
+ function resolveIdentity(spec) {
1668
+ return classifyModel(spec.provider, policyModelId(spec));
1669
+ }
1670
+ let keyRecords;
1671
+ function getKeyRecords() {
1672
+ if (!keyRecords) {
1673
+ keyRecords = {};
1674
+ for (const directive in AXES) {
1675
+ const axis = AXES[directive];
1676
+ if (axis.set === "wire" && axis.records) keyRecords[axis.key] = { records: axis.records };
1677
+ }
1678
+ }
1679
+ return keyRecords;
1680
+ }
1681
+ /**
1682
+ * Assigns resolved wire axes onto a freshly-detected compat record. An axis
1683
+ * lands only when the model's API maps to one of the axis's declared records
1684
+ * — the axes table is the single applicability authority, so optional keys
1685
+ * absent from the detected baseline still land.
1686
+ */
1687
+ function applyWireAxes(compat, wire, api) {
1688
+ const records = API_COMPAT_RECORDS[api];
1689
+ if (!records) return;
1690
+ const info = getKeyRecords();
1691
+ for (const key in wire) {
1692
+ if (!info[key]?.records.some((record) => records.includes(record))) continue;
1693
+ Reflect.set(compat, key, wire[key]);
1694
+ }
1695
+ }
1696
+ /**
1697
+ * Preserves legacy per-key merge semantics for map-valued effort remaps: a
1698
+ * cascade-provided `reasoningEffortMap` is the detected base and sparse spec
1699
+ * overrides overlay it key by key (spec keys win, unseen keys survive).
1700
+ */
1701
+ function overlayEffortMapAxis(compat, axes, specCompat) {
1702
+ const axisMap = effortRecord(axes.wire.reasoningEffortMap);
1703
+ if (axisMap && specCompat?.reasoningEffortMap) compat.reasoningEffortMap = {
1704
+ ...axisMap,
1705
+ ...specCompat.reasoningEffortMap
1706
+ };
1707
+ }
1708
+ function effortList(value) {
1709
+ if (!Array.isArray(value)) return void 0;
1710
+ const out = [];
1711
+ for (const entry of value) {
1712
+ const effort = THINKING_EFFORTS.find((candidate) => candidate === entry);
1713
+ if (effort === void 0) return void 0;
1714
+ out.push(effort);
1715
+ }
1716
+ return out;
1717
+ }
1718
+ function effortValue(value) {
1719
+ return THINKING_EFFORTS.find((candidate) => candidate === value);
1720
+ }
1721
+ function objectPayload(value) {
1722
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
1723
+ }
1724
+ function effortRecord(value) {
1725
+ if (typeof value !== "object" || value === null) return void 0;
1726
+ const out = {};
1727
+ let any = false;
1728
+ for (const key in value) {
1729
+ const effort = effortValue(key);
1730
+ const mapped = Reflect.get(value, key);
1731
+ if (effort === void 0 || typeof mapped !== "string") continue;
1732
+ out[effort] = mapped;
1733
+ any = true;
1734
+ }
1735
+ return any ? out : void 0;
1736
+ }
1737
+ function effortNumberRecord(value) {
1738
+ if (typeof value !== "object" || value === null) return void 0;
1739
+ const out = {};
1740
+ let any = false;
1741
+ for (const key in value) {
1742
+ const effort = effortValue(key);
1743
+ const mapped = Reflect.get(value, key);
1744
+ if (effort === void 0 || typeof mapped !== "number") continue;
1745
+ out[effort] = mapped;
1746
+ any = true;
1747
+ }
1748
+ return any ? out : void 0;
1749
+ }
1750
+ function thinkingMode(value) {
1751
+ switch (value) {
1752
+ case "effort":
1753
+ case "budget":
1754
+ case "google-level":
1755
+ case "anthropic-adaptive":
1756
+ case "anthropic-budget-effort": return value;
1757
+ default: return;
1758
+ }
1759
+ }
1760
+ const GLM_CODING_PLAN_STREAM_IDLE_TIMEOUT_MS = 6e5;
1761
+ const LOCAL_OPENAI_COMPAT_STREAM_IDLE_TIMEOUT_MS = 3e5;
1762
+ const LOCAL_OPENAI_COMPAT_PROVIDERS = {
1763
+ "llama.cpp": true,
1764
+ "lm-studio": true,
1765
+ vllm: true,
1766
+ ollama: true
1767
+ };
1768
+ const PROXY_OPENAI_COMPAT_PROVIDERS = { litellm: true };
1769
+ function hasLocalLoopbackBaseUrl(baseUrl) {
1770
+ if (!baseUrl) return false;
1771
+ let hostname;
1772
+ try {
1773
+ hostname = new URL(baseUrl).hostname.toLowerCase();
1774
+ if (hostname.endsWith(".")) hostname = hostname.slice(0, -1);
1775
+ } catch {
1776
+ return false;
1777
+ }
1778
+ if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1" || hostname === "[::1]") return true;
1779
+ if (hostname.startsWith("10.")) return true;
1780
+ if (hostname.startsWith("192.168.")) return true;
1781
+ if (/^172\.(1[6-9]|2[0-9]|3[01])\./.test(hostname)) return true;
1782
+ if (hostname.endsWith(".local")) return true;
1783
+ return false;
1784
+ }
1785
+ function resolveReasoningDisableMode(thinkingFormat) {
1786
+ switch (thinkingFormat) {
1787
+ case "openrouter": return "openrouter-enabled-false";
1788
+ case "zai":
1789
+ case "kimi": return "zai-thinking-disabled";
1790
+ case "qwen": return "qwen-enable-thinking-false";
1791
+ case "qwen-chat-template": return "qwen-template-false";
1792
+ case "chat-template": return "chat-template-thinking-false";
1793
+ default: return "lowest-effort";
1794
+ }
1795
+ }
1796
+ /** Strict official-OpenAI check: provider id `openai` and an `api.openai.com` host. */
1797
+ function isOfficialOpenAIEndpoint(provider, baseUrl) {
1798
+ if (provider !== "openai") return false;
1799
+ if (!baseUrl) return true;
1800
+ try {
1801
+ return new URL(baseUrl).hostname === "api.openai.com";
1802
+ } catch {
1803
+ return false;
1804
+ }
1805
+ }
1806
+ function detectOpenAI(spec, facts, reasoningCapable) {
1807
+ const provider = spec.provider;
1808
+ const backendProvider = spec.providerType ?? provider;
1809
+ const baseUrl = spec.baseUrl;
1810
+ const hostModel = {
1811
+ provider,
1812
+ baseUrl
1813
+ };
1814
+ const isZai = modelMatchesHost(hostModel, "zai");
1815
+ const isZhipu = modelMatchesHost(hostModel, "zhipu");
1816
+ const isMoonshotNative = modelMatchesHost(hostModel, "moonshotNative");
1817
+ const isXiaomiHost = modelMatchesHost(hostModel, "xiaomi");
1818
+ const isDirectDeepseekApi = modelMatchesHost(hostModel, "deepseekDirect");
1819
+ const isDeepseekReasoning = (modelMatchesHost(hostModel, "deepseekFamily") || facts.is("deepseek")) && reasoningCapable;
1820
+ const isLocalOpenAICompatBackend = PROXY_OPENAI_COMPAT_PROVIDERS[backendProvider] !== true && (LOCAL_OPENAI_COMPAT_PROVIDERS[backendProvider] === true || hasLocalLoopbackBaseUrl(baseUrl));
1821
+ return {
1822
+ facts,
1823
+ isZai,
1824
+ isZhipu,
1825
+ isMoonshotNative,
1826
+ isOpenCodeHost: modelMatchesHost(hostModel, "opencode"),
1827
+ isOpenCodeProvider: provider === "opencode-go" || provider === "opencode-zen",
1828
+ isDirectDeepseekApi,
1829
+ isDeepseekReasoning,
1830
+ isDirectDeepseekReasoning: isDirectDeepseekApi && isDeepseekReasoning,
1831
+ isVenice: modelMatchesHost(hostModel, "venice"),
1832
+ requiresEnabledThinking: isMoonshotNative && facts.is("kimi") && facts.family("k2.7-code"),
1833
+ isXiaomiMimo: isXiaomiHost && facts.is("mimo"),
1834
+ isLocalOpenAICompatBackend,
1835
+ isLocalServingBackend: isLocalOpenAICompatBackend || hasLocalLoopbackBaseUrl(baseUrl),
1836
+ isOpenRouter: modelMatchesHost(hostModel, "openrouter")
1837
+ };
1838
+ }
1839
+ /**
1840
+ * Detected chat-completions baseline. Pure identity policy (Kimi max-token
1841
+ * behavior, DeepSeek reasoning-content contracts, Qwen dialects, sampling
1842
+ * restrictions, effort maps, markup healers, …) is rule-owned and absent
1843
+ * here; compound host×identity branches remain, keyed on identity fields.
1844
+ */
1845
+ function detectOpenAICompat(spec, d, reasoningCapable) {
1846
+ const provider = spec.provider;
1847
+ const baseUrl = spec.baseUrl;
1848
+ const hostModel = {
1849
+ provider,
1850
+ baseUrl
1851
+ };
1852
+ const facts = d.facts;
1853
+ const isCerebras = modelMatchesHost(hostModel, "cerebras");
1854
+ const isCerebrasHost = hostMatchesUrl(baseUrl, "cerebras");
1855
+ const isKilo = modelMatchesHost(hostModel, "kilo");
1856
+ const isAlibaba = modelMatchesHost(hostModel, "alibabaDashscope");
1857
+ const isXiaomiHost = modelMatchesHost(hostModel, "xiaomi");
1858
+ const isGrok = modelMatchesHost(hostModel, "xai");
1859
+ const isMistral = modelMatchesHost(hostModel, "mistral");
1860
+ const isGoogleAistudioOpenAI = hostMatchesUrl(baseUrl, "googleAistudio");
1861
+ const isOpenAIHost = modelMatchesHost(hostModel, "openai");
1862
+ const isAzureHost = modelMatchesHost(hostModel, "azureOpenAI");
1863
+ const isVercelGateway = modelMatchesHost(hostModel, "vercelAIGateway");
1864
+ const isTogether = modelMatchesHost(hostModel, "together");
1865
+ const isFireworks = hostMatchesUrl(baseUrl, "fireworks");
1866
+ const isGroqHost = modelMatchesHost(hostModel, "groq");
1867
+ const isMiniMaxHost = modelMatchesHost(hostModel, "minimax");
1868
+ const isQwenPortal = modelMatchesHost(hostModel, "qwenPortal");
1869
+ const isMoonshotKimi = facts.is("kimi") && d.isMoonshotNative;
1870
+ const isMoonshotKimiK3 = isMoonshotKimi && facts.family("k3");
1871
+ const usesMoonshotKimiPreservedThinking = isMoonshotKimi && facts.family("k2.6");
1872
+ const isAnthropicModel = modelMatchesHost(hostModel, "anthropic") || facts.is("anthropic");
1873
+ const isQwen = facts.is("qwen");
1874
+ const isDeepseekFamily = modelMatchesHost(hostModel, "deepseekFamily") || facts.is("deepseek");
1875
+ const supportsZaiReasoningEffort = (d.isZai || d.isZhipu) && facts.is("glm") && facts.revGte("5.2");
1876
+ const isNonStandard = isCerebras || isGrok || isMistral || isGoogleAistudioOpenAI || hostMatchesUrl(baseUrl, "chutes") || hostMatchesUrl(baseUrl, "deepseekFamily") || isFireworks || isAlibaba || d.isZai || d.isZhipu || isKilo || isQwen || isXiaomiHost || d.isMoonshotNative || d.isOpenCodeHost;
1877
+ const useMaxTokens = isMistral || d.isMoonshotNative || d.isZai || d.isZhipu || hostMatchesUrl(baseUrl, "chutes") || isFireworks || d.isDirectDeepseekApi;
1878
+ const supportsPromptCacheBreakpoints = isOfficialOpenAIEndpoint(provider, baseUrl) && facts.is("openai") && facts.revGte("5.6");
1879
+ const supportsMultipleSystemMessagesDefault = !isMiniMaxHost && !isAlibaba && !isQwenPortal && !isQwen && (isOpenAIHost || isAzureHost || d.isOpenRouter || isCerebras || isTogether || isFireworks || isGroqHost || isDeepseekFamily || isMistral || isGrok || d.isZai || d.isZhipu || provider === "github-copilot" || provider === "zenmux");
1880
+ const streamIdleTimeoutMs = facts.is("glm") && facts.revGte("5") && !facts.family("vision") && (hostMatchesUrl(baseUrl, "zai") || hostMatchesUrl(baseUrl, "zhipu") || hostMatchesUrl(baseUrl, "opencode")) ? GLM_CODING_PLAN_STREAM_IDLE_TIMEOUT_MS : facts.is("mimo") && hostMatchesUrl(baseUrl, "xiaomi") ? 3e5 : reasoningCapable && facts.is("kimi") && (facts.family("k3") || facts.family("k2.7-code")) && hostMatchesUrl(baseUrl, "moonshotNative") ? 3e5 : reasoningCapable && facts.is("deepseek") && hostMatchesUrl(baseUrl, "deepseekDirect") ? 3e5 : d.isLocalServingBackend ? LOCAL_OPENAI_COMPAT_STREAM_IDLE_TIMEOUT_MS : void 0;
1881
+ const wireModelIdMode = hostMatchesUrl(baseUrl, "openrouter") ? "openrouter" : "raw";
1882
+ const thinkingFormat = facts.is("kimi") && !facts.family("k3") && hostMatchesUrl(baseUrl, "moonshotNative") || hostMatchesUrl(baseUrl, "zai") || hostMatchesUrl(baseUrl, "zhipu") || facts.is("mimo") && hostMatchesUrl(baseUrl, "xiaomi") ? "zai" : hostMatchesUrl(baseUrl, "openrouter") ? "openrouter" : isQwen && hostMatchesUrl(baseUrl, "nvidia") ? "qwen-chat-template" : isQwen && (isFireworks || hostMatchesUrl(baseUrl, "venice")) ? "openai" : hostMatchesUrl(baseUrl, "alibabaDashscope") || isQwen ? "qwen" : "openai";
1883
+ return {
1884
+ supportsStore: !isNonStandard,
1885
+ supportsDeveloperRole: isOpenAIHost || isAzureHost,
1886
+ supportsMultipleSystemMessages: supportsMultipleSystemMessagesDefault,
1887
+ supportsReasoningEffort: !isGrok && !d.isXiaomiMimo && (!(d.isZai || d.isZhipu) || supportsZaiReasoningEffort),
1888
+ trustExplicitThinkingOnly: void 0,
1889
+ supportsReasoningParams: true,
1890
+ supportsSamplingParams: true,
1891
+ supportsPenaltyAndStopParams: !(isGrok && reasoningCapable),
1892
+ reasoningEffortMap: {},
1893
+ supportsUsageInStreaming: !isCerebrasHost,
1894
+ alwaysSendMaxTokens: facts.is("kimi"),
1895
+ disableReasoningOnForcedToolChoice: facts.is("kimi") && !isMoonshotKimiK3 || isAnthropicModel,
1896
+ disableReasoningOnToolChoice: isDeepseekFamily && reasoningCapable && !d.isOpenRouter,
1897
+ disableReasoningWithTools: false,
1898
+ supportsToolChoice: !d.isDirectDeepseekReasoning,
1899
+ supportsForcedToolChoice: !d.requiresEnabledThinking && !(d.isOpenCodeHost && d.isDeepseekReasoning),
1900
+ supportsNamedToolChoice: true,
1901
+ maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens",
1902
+ requiresToolResultName: isMistral,
1903
+ requiresAssistantAfterToolResult: isMistral,
1904
+ requiresThinkingAsText: isMistral,
1905
+ requiresMistralToolIds: isMistral,
1906
+ thinkingFormat,
1907
+ kimiApiFormat: void 0,
1908
+ reasoningDisableMode: d.isVenice ? "venice-disable-thinking" : resolveReasoningDisableMode(thinkingFormat),
1909
+ omitReasoningEffort: false,
1910
+ includeEncryptedReasoning: true,
1911
+ filterReasoningHistory: d.isOpenRouter && isAnthropicModel,
1912
+ thinkingKeep: usesMoonshotKimiPreservedThinking ? "all" : void 0,
1913
+ reasoningContentField: "reasoning_content",
1914
+ mistralReasoningContentParts: void 0,
1915
+ requiresReasoningContentForToolCalls: facts.is("kimi") && !d.isOpenCodeProvider || isDeepseekFamily && reasoningCapable || d.isXiaomiMimo || d.isOpenRouter && reasoningCapable,
1916
+ requiresReasoningContentForAllAssistantTurns: (isDeepseekFamily && reasoningCapable || d.isXiaomiMimo) && !d.isOpenRouter,
1917
+ allowsSyntheticReasoningContentForToolCalls: (!isDeepseekFamily || !reasoningCapable) && !d.isXiaomiMimo,
1918
+ syntheticReasoningContentFallback: void 0,
1919
+ replayReasoningContent: d.isLocalOpenAICompatBackend,
1920
+ qwenPreserveThinking: (thinkingFormat === "qwen" || thinkingFormat === "qwen-chat-template") && d.isLocalOpenAICompatBackend,
1921
+ qwenTemplateReasoningEffort: false,
1922
+ requiresAssistantContentForToolCalls: facts.is("kimi") || d.isDirectDeepseekReasoning,
1923
+ cacheControlFormat: d.isOpenRouter && isAnthropicModel ? "anthropic" : void 0,
1924
+ supportsPromptCacheBreakpoints,
1925
+ promptCacheBreakpointTtl: supportsPromptCacheBreakpoints ? "30m" : void 0,
1926
+ openRouterRouting: void 0,
1927
+ vercelGatewayRouting: void 0,
1928
+ isOpenRouterHost: d.isOpenRouter,
1929
+ wireModelIdMode,
1930
+ isVercelGatewayHost: isVercelGateway,
1931
+ supportsStrictMode: hostMatchesUrl(baseUrl, "openai") || hostMatchesUrl(baseUrl, "azureOpenAI") || hostMatchesUrl(baseUrl, "cerebras") || hostMatchesUrl(baseUrl, "together") || hostMatchesUrl(baseUrl, "openrouter") || hostMatchesUrl(baseUrl, "deepseekFamily"),
1932
+ extraBody: void 0,
1933
+ toolStrictMode: isCerebrasHost ? "all_strict" : "mixed",
1934
+ toolSchemaFlavor: d.isMoonshotNative || facts.is("kimi") ? "moonshot-mfjs" : d.isLocalOpenAICompatBackend ? "grammar" : void 0,
1935
+ streamFirstEventTimeoutMs: d.isLocalServingBackend ? 0 : void 0,
1936
+ streamIdleTimeoutMs,
1937
+ stripDeepseekSpecialTokens: false,
1938
+ stripThinkingHistory: void 0,
1939
+ officialEndpoint: isOfficialOpenAIEndpoint(spec.provider, baseUrl) || void 0,
1940
+ streamMarkupHealingPattern: detectStreamMarkupHealing(spec.provider, facts, baseUrl),
1941
+ reasoningDeltasMayBeCumulative: false,
1942
+ emptyLengthFinishIsContextError: false,
1943
+ usesOpenAIToolCallIdLimit: false,
1944
+ promptCacheSessionHeader: hostMatchesUrl(baseUrl, "xai") ? "x-grok-conv-id" : void 0,
1945
+ dropThinkingWhenReasoningEffort: false,
1946
+ nativeKimiK3Reasoning: false,
1947
+ zaiReasoningEffortDialect: false,
1948
+ clampOutputToModelMax: d.isLocalOpenAICompatBackend,
1949
+ stripImageInput: false,
1950
+ thinkingLoopGuard: void 0,
1951
+ rejectRootObjectUnion: false,
1952
+ retryWithoutStrictOnGrammarError: false,
1953
+ supportsPromptCacheKey: false
1954
+ };
1955
+ }
1956
+ /**
1957
+ * Default leaked-markup healer. Kimi/DeepSeek dedicated grammars are keyed on
1958
+ * identity class; official OpenAI heals nothing; everything else defaults to
1959
+ * the generic `thinking` healer. DSML is DeepSeek's own tool-call grammar, so
1960
+ * every host serving a DeepSeek model gets it — gateways, local backends, and
1961
+ * custom providers alike.
1962
+ */
1963
+ function detectStreamMarkupHealing(provider, facts, baseUrl) {
1964
+ const isKimiK2 = facts.is("kimi") && facts.identity.family?.startsWith("k2") === true;
1965
+ if (provider === "kimi-code" || provider === "moonshot" || isKimiK2) return "kimi";
1966
+ if (facts.is("deepseek")) return "dsml";
1967
+ if (isOfficialOpenAIEndpoint(provider, baseUrl)) return void 0;
1968
+ return "thinking";
1969
+ }
1970
+ function fixupOpenAICompat(spec, compat, d, axes) {
1971
+ const deepseekThinking = compat.extraBody?.thinking;
1972
+ if (d.isDirectDeepseekReasoning && typeof deepseekThinking === "object" && deepseekThinking !== null && "type" in deepseekThinking && deepseekThinking.type === "enabled") {
1973
+ const extraBody = { ...compat.extraBody };
1974
+ delete extraBody.thinking;
1975
+ compat.extraBody = Object.keys(extraBody).length > 0 ? extraBody : void 0;
1976
+ }
1977
+ if (spec.compat?.reasoningDisableMode === void 0 && !("reasoningDisableMode" in axes.wire)) compat.reasoningDisableMode = d.requiresEnabledThinking ? "omit" : d.isDirectDeepseekReasoning ? "zai-thinking-disabled" : d.isVenice ? "venice-disable-thinking" : resolveReasoningDisableMode(compat.thinkingFormat);
1978
+ if (spec.compat?.omitReasoningEffort === void 0 && !("omitReasoningEffort" in axes.wire) && !compat.supportsReasoningEffort) compat.omitReasoningEffort = true;
1979
+ const axisWhenThinking = compatReasoning(spec, axes) ? objectPayload(axes.wire.whenThinking) : void 0;
1980
+ const whenThinkingPolicy = spec.compat?.whenThinking ?? axisWhenThinking ?? (d.isDirectDeepseekReasoning ? { extraBody: {
1981
+ ...compat.extraBody,
1982
+ thinking: { type: "enabled" }
1983
+ } } : void 0);
1984
+ if (whenThinkingPolicy) {
1985
+ const variant = {
1986
+ ...compat,
1987
+ whenThinking: void 0
1988
+ };
1989
+ applyCompatOverrides(variant, whenThinkingPolicy);
1990
+ if (Reflect.get(whenThinkingPolicy, "reasoningDisableMode") === void 0) variant.reasoningDisableMode = d.isVenice ? "venice-disable-thinking" : resolveReasoningDisableMode(variant.thinkingFormat);
1991
+ if (Reflect.get(whenThinkingPolicy, "omitReasoningEffort") === void 0 && !variant.supportsReasoningEffort) variant.omitReasoningEffort = true;
1992
+ compat.whenThinking = variant;
1993
+ } else compat.whenThinking = void 0;
1994
+ }
1995
+ function resolveOpenAICompletionsPolicy(spec, facts, axes) {
1996
+ const reasoningCapable = compatReasoning(spec, axes);
1997
+ const d = detectOpenAI(spec, facts, reasoningCapable);
1998
+ const compat = detectOpenAICompat(spec, d, reasoningCapable);
1999
+ applyWireAxes(compat, axes.wire, "openai-completions");
2000
+ applyCompatOverrides(compat, spec.compat);
2001
+ overlayEffortMapAxis(compat, axes, spec.compat);
2002
+ fixupOpenAICompat(spec, compat, d, axes);
2003
+ return compat;
2004
+ }
2005
+ /** Detected Responses-API baseline (ported from `buildOpenAIResponsesCompat`). */
2006
+ function resolveOpenAIResponsesPolicy(spec, facts, axes, api) {
2007
+ const baseUrl = spec.baseUrl ?? "";
2008
+ const provider = spec.provider;
2009
+ const backendProvider = spec.providerType ?? provider;
2010
+ const hostModel = {
2011
+ provider,
2012
+ baseUrl
2013
+ };
2014
+ const isAzure = modelMatchesHost(hostModel, "azureOpenAI");
2015
+ const isOpenRouter = modelMatchesHost(hostModel, "openrouter");
2016
+ const isOpenAIUrl = hostMatchesUrl(baseUrl, "openai");
2017
+ const isVercelGateway = modelMatchesHost(hostModel, "vercelAIGateway");
2018
+ const isXaiHost = modelMatchesHost(hostModel, "xai");
2019
+ const supportsPromptCacheBreakpoints = isOfficialOpenAIEndpoint(provider, baseUrl) && facts.is("openai") && facts.revGte("5.6");
2020
+ const thinkingFormat = isOpenRouter ? "openrouter" : "openai";
2021
+ const reasoningCapable = compatReasoning(spec, axes);
2022
+ const isLocalServingBackend = PROXY_OPENAI_COMPAT_PROVIDERS[backendProvider] !== true && LOCAL_OPENAI_COMPAT_PROVIDERS[backendProvider] === true || hasLocalLoopbackBaseUrl(baseUrl);
2023
+ const isAnthropicModel = facts.is("anthropic");
2024
+ const isDeepseekFamily = facts.is("deepseek");
2025
+ const compat = {
2026
+ supportsDeveloperRole: isAzure || isOpenAIUrl || hostMatchesUrl(baseUrl, "githubCopilot"),
2027
+ supportsStrictMode: isAzure || hostMatchesUrl(baseUrl, "openai") || hostMatchesUrl(baseUrl, "azureOpenAI") || hostMatchesUrl(baseUrl, "cerebras") || hostMatchesUrl(baseUrl, "together") || hostMatchesUrl(baseUrl, "openrouter") || hostMatchesUrl(baseUrl, "deepseekFamily"),
2028
+ supportsReasoningEffort: !isXaiHost,
2029
+ trustExplicitThinkingOnly: void 0,
2030
+ supportsLongPromptCacheRetention: isOpenAIUrl,
2031
+ supportsPromptCacheBreakpoints,
2032
+ promptCacheBreakpointTtl: supportsPromptCacheBreakpoints ? "30m" : void 0,
2033
+ strictResponsesPairing: hostMatchesUrl(baseUrl, "azureOpenAI"),
2034
+ supportsImageDetailOriginal: isOpenAIUrl || hostMatchesUrl(baseUrl, "azureOpenAI") || isAzure && !baseUrl || hostMatchesUrl(baseUrl, "openaiCodex"),
2035
+ supportsReasoningSummary: !isXaiHost,
2036
+ statefulResponses: void 0,
2037
+ supportsAllTurnsReasoningContext: false,
2038
+ supportsConfigurationUpdate: false,
2039
+ supportsSteering: false,
2040
+ requiresReasoningOffJuiceInstruction: false,
2041
+ stripImageInput: false,
2042
+ thinkingLoopGuard: void 0,
2043
+ reasoningEffortMap: {},
2044
+ supportsReasoningParams: true,
2045
+ supportsSamplingParams: true,
2046
+ supportsPenaltyAndStopParams: !isXaiHost,
2047
+ thinkingFormat,
2048
+ reasoningDisableMode: resolveReasoningDisableMode(thinkingFormat),
2049
+ omitReasoningEffort: false,
2050
+ includeEncryptedReasoning: true,
2051
+ filterReasoningHistory: isOpenRouter && isAnthropicModel,
2052
+ disableReasoningOnForcedToolChoice: facts.is("kimi"),
2053
+ disableReasoningOnToolChoice: isDeepseekFamily && reasoningCapable && !isOpenRouter,
2054
+ disableReasoningWithTools: false,
2055
+ supportsToolChoice: true,
2056
+ supportsForcedToolChoice: true,
2057
+ supportsNamedToolChoice: true,
2058
+ reasoningContentField: "reasoning_content",
2059
+ requiresReasoningContentForToolCalls: (facts.is("kimi") || isDeepseekFamily && reasoningCapable || isOpenRouter && reasoningCapable) && reasoningCapable,
2060
+ requiresReasoningContentForAllAssistantTurns: isDeepseekFamily && reasoningCapable && !isOpenRouter,
2061
+ allowsSyntheticReasoningContentForToolCalls: !isDeepseekFamily || !reasoningCapable,
2062
+ syntheticReasoningContentFallback: void 0,
2063
+ replayReasoningContent: false,
2064
+ qwenPreserveThinking: false,
2065
+ qwenTemplateReasoningEffort: false,
2066
+ requiresThinkingAsText: false,
2067
+ requiresMistralToolIds: false,
2068
+ requiresToolResultName: false,
2069
+ requiresAssistantAfterToolResult: false,
2070
+ requiresAssistantContentForToolCalls: facts.is("kimi"),
2071
+ openRouterRouting: void 0,
2072
+ vercelGatewayRouting: void 0,
2073
+ isOpenRouterHost: isOpenRouter,
2074
+ isVercelGatewayHost: isVercelGateway,
2075
+ wireModelIdMode: isOpenRouter ? "openrouter" : "raw",
2076
+ toolSchemaFlavor: facts.is("kimi") ? "moonshot-mfjs" : void 0,
2077
+ alwaysSendMaxTokens: facts.is("kimi"),
2078
+ clampOutputToModelMax: PROXY_OPENAI_COMPAT_PROVIDERS[backendProvider] !== true && (LOCAL_OPENAI_COMPAT_PROVIDERS[backendProvider] === true || hasLocalLoopbackBaseUrl(baseUrl)),
2079
+ supportsObfuscationOptOut: isOpenAIUrl || provider === "openai",
2080
+ storeResponses: false,
2081
+ connectionBoundNativeHistory: false,
2082
+ officialEndpoint: isOfficialOpenAIEndpoint(provider, baseUrl) || api === "openai-codex-responses" && isOfficialCodexApiUrl(baseUrl),
2083
+ harmonyLeakMitigation: false,
2084
+ rejectRootObjectUnion: false,
2085
+ retryWithoutStrictOnGrammarError: false,
2086
+ cacheControlFormat: isOpenRouter && isAnthropicModel ? "anthropic" : void 0,
2087
+ stripDeepseekSpecialTokens: false,
2088
+ streamMarkupHealingPattern: detectStreamMarkupHealing(provider, facts, baseUrl),
2089
+ reasoningDeltasMayBeCumulative: false,
2090
+ emptyLengthFinishIsContextError: false,
2091
+ usesOpenAIToolCallIdLimit: false,
2092
+ promptCacheSessionHeader: hostMatchesUrl(baseUrl, "xai") ? "x-grok-conv-id" : void 0,
2093
+ streamFirstEventTimeoutMs: isLocalServingBackend ? 0 : spec.compat?.streamFirstEventTimeoutMs,
2094
+ streamIdleTimeoutMs: isLocalServingBackend ? LOCAL_OPENAI_COMPAT_STREAM_IDLE_TIMEOUT_MS : spec.compat?.streamIdleTimeoutMs
2095
+ };
2096
+ applyWireAxes(compat, axes.wire, api);
2097
+ applyCompatOverrides(compat, spec.compat);
2098
+ overlayEffortMapAxis(compat, axes, spec.compat);
2099
+ if (isXaiHost && "reasoningEffortMap" in axes.wire) {
2100
+ const canonical = effortRecord(axes.wire.reasoningEffortMap) ?? {};
2101
+ compat.reasoningEffortMap = {
2102
+ ...compat.reasoningEffortMap,
2103
+ ...canonical
2104
+ };
2105
+ for (const key of ["xhigh", "max"]) if (!(key in canonical)) delete compat.reasoningEffortMap[key];
2106
+ }
2107
+ if (spec.compat?.reasoningDisableMode === void 0 && !("reasoningDisableMode" in axes.wire)) compat.reasoningDisableMode = resolveReasoningDisableMode(compat.thinkingFormat);
2108
+ if (spec.compat?.omitReasoningEffort === void 0 && !("omitReasoningEffort" in axes.wire) && !compat.supportsReasoningEffort) compat.omitReasoningEffort = true;
2109
+ if (provider === "xai-oauth" && axes.wire.supportsReasoningEffort === true && spec.compat?.supportsReasoningEffort !== false) {
2110
+ compat.supportsReasoningEffort = true;
2111
+ compat.omitReasoningEffort = false;
2112
+ }
2113
+ return compat;
2114
+ }
2115
+ function pickResponsesOnly(compat) {
2116
+ return {
2117
+ supportsLongPromptCacheRetention: compat.supportsLongPromptCacheRetention,
2118
+ strictResponsesPairing: compat.strictResponsesPairing,
2119
+ supportsImageDetailOriginal: compat.supportsImageDetailOriginal,
2120
+ supportsObfuscationOptOut: compat.supportsObfuscationOptOut,
2121
+ storeResponses: compat.storeResponses,
2122
+ connectionBoundNativeHistory: compat.connectionBoundNativeHistory,
2123
+ supportsAllTurnsReasoningContext: compat.supportsAllTurnsReasoningContext,
2124
+ supportsConfigurationUpdate: compat.supportsConfigurationUpdate,
2125
+ supportsSteering: compat.supportsSteering,
2126
+ officialEndpoint: compat.officialEndpoint,
2127
+ harmonyLeakMitigation: compat.harmonyLeakMitigation,
2128
+ cacheControlFormat: compat.cacheControlFormat,
2129
+ requiresReasoningOffJuiceInstruction: compat.requiresReasoningOffJuiceInstruction,
2130
+ supportsReasoningSummary: compat.supportsReasoningSummary,
2131
+ statefulResponses: compat.statefulResponses,
2132
+ isVercelGatewayHost: compat.isVercelGatewayHost
2133
+ };
2134
+ }
2135
+ function resolveAnthropicPolicy(spec, facts, axes) {
2136
+ const baseUrl = spec.baseUrl;
2137
+ const official = isOfficialAnthropicApiUrl(baseUrl);
2138
+ const isCopilot = modelMatchesHost(spec, "githubCopilot");
2139
+ const isZenmux = modelMatchesHost(spec, "zenmux");
2140
+ const requiresThinkingEnabled = modelMatchesHost(spec, "moonshotNative") && facts.kimiMandatoryThinking;
2141
+ const bedrockMessagesApi = isBedrockAnthropicRoute(baseUrl);
2142
+ const rejectsStrictTools = isAzureAnthropicRoute(baseUrl) || bedrockMessagesApi;
2143
+ const signingEndpoint = official || isCopilot || isZenmux || isAnthropicSigningProxyUrl(baseUrl);
2144
+ const compat = {
2145
+ officialEndpoint: official,
2146
+ signingEndpoint,
2147
+ supportsContextManagement: true,
2148
+ supportsServerCompaction: false,
2149
+ firstPartyProvider: false,
2150
+ honorsClaudeCodeBetaKillSwitch: false,
2151
+ supportsOutputEffort: true,
2152
+ disableStrictTools: rejectsStrictTools,
2153
+ bedrockMessagesApi: bedrockMessagesApi || void 0,
2154
+ disableAdaptiveThinking: false,
2155
+ allowAnthropicHeaderOverrides: false,
2156
+ supportsEagerToolInputStreaming: official,
2157
+ supportsLongCacheRetention: official,
2158
+ supportsMidConversationSystem: official && !facts.family("sonnet") && facts.anthropicAdaptiveGenAtLeast("4.8"),
2159
+ supportsTurnScopedSystem: false,
2160
+ supportsMidConversationToolChanges: false,
2161
+ supportsPerMessageEffort: false,
2162
+ supportsThinkingBindingControls: false,
2163
+ supportsBetweenToolsThinking: false,
2164
+ supportsForcedToolChoice: !requiresThinkingEnabled && !facts.family("fable", "mythos"),
2165
+ supportsSamplingParams: true,
2166
+ requiresToolResultId: false,
2167
+ requiresThinkingEnabled,
2168
+ replayUnsignedThinking: !signingEndpoint && (compatReasoning(spec, axes) || modelMatchesHost(spec, "deepseekFamily")),
2169
+ escapeBuiltinToolNames: false,
2170
+ injectClaudeCodeInstruction: true,
2171
+ stripImageInput: false,
2172
+ maxImageDimension: void 0,
2173
+ maxImagePayloadBytes: void 0,
2174
+ thinkingLoopGuard: void 0,
2175
+ stripThinkingHistory: void 0,
2176
+ fastMode: void 0,
2177
+ streamIdleTimeoutMs: spec.compat?.streamIdleTimeoutMs
2178
+ };
2179
+ applyWireAxes(compat, axes.wire, "anthropic-messages");
2180
+ applyCompatOverrides(compat, spec.compat);
2181
+ return compat;
2182
+ }
2183
+ const BEDROCK_REASONING_STREAM_IDLE_TIMEOUT_MS = 6e5;
2184
+ function resolveBedrockPolicy(spec, axes) {
2185
+ const compat = {
2186
+ promptCacheMode: "none",
2187
+ supportsServerCompaction: false,
2188
+ supportsLongPromptCacheRetention: false,
2189
+ promptCacheMinimumTokens: 0,
2190
+ promptCacheMaximumCheckpoints: 0,
2191
+ supportsForcedToolChoice: true,
2192
+ supportsThinkingBindingControls: true
2193
+ };
2194
+ compat.streamIdleTimeoutMs = compatReasoning(spec, axes) ? BEDROCK_REASONING_STREAM_IDLE_TIMEOUT_MS : void 0;
2195
+ applyWireAxes(compat, axes.wire, "bedrock-converse-stream");
2196
+ applyCompatOverrides(compat, spec.compat);
2197
+ return compat;
2198
+ }
2199
+ function resolveOllamaPolicy(spec, axes) {
2200
+ const compat = { stripThinkingHistory: false };
2201
+ applyWireAxes(compat, axes.wire, "ollama-chat");
2202
+ applyCompatOverrides(compat, spec.compat);
2203
+ return compat;
2204
+ }
2205
+ function resolveDevinPolicy(spec, axes) {
2206
+ const compat = {
2207
+ trustExplicitThinkingOnly: false,
2208
+ modelRouter: false,
2209
+ supportsParallelToolCalls: false
2210
+ };
2211
+ applyWireAxes(compat, axes.wire, "devin-agent");
2212
+ applyCompatOverrides(compat, spec.compat);
2213
+ return compat;
2214
+ }
2215
+ function resolveGooglePolicy(spec, axes) {
2216
+ const compat = {
2217
+ supportsFunctionPartId: false,
2218
+ requiresSkipThoughtSignature: false,
2219
+ requiresSkipThoughtSignatureOnFirstFunctionCall: false,
2220
+ dropUnsignedThinking: false,
2221
+ ccaLegacyParametersSchema: false,
2222
+ multimodalFunctionResponse: false,
2223
+ flashStreamLeakWorkaround: false,
2224
+ claudeThinkingBetaHeader: false,
2225
+ antigravityClaudeToolMode: false,
2226
+ stripImageInput: false,
2227
+ maxImageDimension: void 0,
2228
+ maxImagePayloadBytes: void 0
2229
+ };
2230
+ applyWireAxes(compat, axes.wire, spec.api);
2231
+ applyCompatOverrides(compat, spec.compat);
2232
+ return compat;
2233
+ }
2234
+ const DEFAULT_REASONING_EFFORTS = [
2235
+ "minimal",
2236
+ "low",
2237
+ "medium",
2238
+ "high"
2239
+ ];
2240
+ const DEFAULT_REASONING_EFFORTS_WITH_XHIGH = [...DEFAULT_REASONING_EFFORTS, "xhigh"];
2241
+ function omitsWireReasoningEffort(api, compat) {
2242
+ if (api !== "openai-responses" && api !== "openai-codex-responses" && api !== "azure-openai-responses") return false;
2243
+ return compat !== void 0 && "supportsReasoningEffort" in compat && compat.supportsReasoningEffort === false;
2244
+ }
2245
+ function readCompatEffortMap(compat) {
2246
+ if (compat === void 0 || !("reasoningEffortMap" in compat)) return void 0;
2247
+ const map = compat.reasoningEffortMap;
2248
+ return map && Object.keys(map).length > 0 ? map : void 0;
2249
+ }
2250
+ /**
2251
+ * URL-keyed Fireworks effort remap: covers custom provider ids pointed at the
2252
+ * Fireworks host, which the `fireworks`/`firepass` `thinking-effort-map`
2253
+ * rules cannot match. Rule and configured maps override it.
2254
+ */
2255
+ const FIREWORKS_THINKING_EFFORT_MAP = { ["minimal"]: "none" };
2256
+ /** Identity/API-derived default control mode; `thinking-mode` rules override. */
2257
+ function defaultThinkingMode(spec, facts) {
2258
+ switch (spec.api) {
2259
+ case "google-generative-ai":
2260
+ case "google-gemini-cli":
2261
+ case "google-vertex": return "budget";
2262
+ case "anthropic-messages":
2263
+ if (facts.is("anthropic")) {
2264
+ if (facts.revGte(facts.family("haiku") ? "5.5" : "4.6")) return "anthropic-adaptive";
2265
+ if (facts.family("opus") && facts.revGte("4.5")) return "anthropic-budget-effort";
2266
+ }
2267
+ return "budget";
2268
+ case "bedrock-converse-stream":
2269
+ if (facts.is("anthropic")) {
2270
+ if (facts.anthropicAdaptiveGenAtLeast("4.6")) return "anthropic-adaptive";
2271
+ if (facts.family("opus") && facts.revGte("4.5")) return "anthropic-budget-effort";
2272
+ }
2273
+ if (facts.is("openai")) return "effort";
2274
+ return "budget";
2275
+ default: return "effort";
2276
+ }
2277
+ }
2278
+ /** API/compat-generic fallback ladder for targets no rule covered. */
2279
+ function fallbackEfforts(spec, compat) {
2280
+ if (spec.api === "anthropic-messages") return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
2281
+ if (spec.api === "bedrock-converse-stream") return DEFAULT_REASONING_EFFORTS;
2282
+ if ((spec.api === "openai-completions" || spec.api === "openrouter") && compat !== void 0 && "thinkingFormat" in compat) {
2283
+ if (compat.thinkingFormat === "openai" && compat.supportsReasoningEffort) return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
2284
+ return DEFAULT_REASONING_EFFORTS;
2285
+ }
2286
+ if (spec.api === "openai-responses" || spec.api === "openai-codex-responses" || spec.api === "azure-openai-responses") return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
2287
+ return DEFAULT_REASONING_EFFORTS;
2288
+ }
2289
+ function filterEffortMap(map, efforts) {
2290
+ let filtered;
2291
+ for (const effort of efforts) {
2292
+ const mapped = map[effort];
2293
+ if (mapped === void 0) continue;
2294
+ filtered ??= {};
2295
+ filtered[effort] = mapped;
2296
+ }
2297
+ return filtered;
2298
+ }
2299
+ function readRuleThinking(axes) {
2300
+ const raw = axes.thinking;
2301
+ const out = {};
2302
+ const mode = thinkingMode(raw.mode);
2303
+ if (mode !== void 0) out.mode = mode;
2304
+ const efforts = effortList(raw.efforts);
2305
+ if (efforts !== void 0) out.efforts = efforts;
2306
+ const defaultLevel = effortValue(raw.defaultLevel);
2307
+ if (defaultLevel !== void 0) out.defaultLevel = defaultLevel;
2308
+ const effortMap = effortRecord(raw.effortMap);
2309
+ if (effortMap !== void 0) out.effortMap = effortMap;
2310
+ const effortBudgets = effortNumberRecord(raw.effortBudgets);
2311
+ if (effortBudgets !== void 0) out.effortBudgets = effortBudgets;
2312
+ if (typeof raw.requiresEffort === "boolean") out.requiresEffort = raw.requiresEffort;
2313
+ if (typeof raw.suppressWhenOff === "boolean") out.suppressWhenOff = raw.suppressWhenOff;
2314
+ if (typeof raw.supportsDisplay === "boolean") out.supportsDisplay = raw.supportsDisplay;
2315
+ if (typeof raw.prefixBinding === "boolean") out.prefixBinding = raw.prefixBinding;
2316
+ if (typeof raw.upgradeNeutral === "boolean") out.upgradeNeutral = raw.upgradeNeutral;
2317
+ if (typeof raw.unverified === "boolean") out.unverified = raw.unverified;
2318
+ return out;
2319
+ }
2320
+ /**
2321
+ * Compat-time reasoning capability. `axes.reasoning` also promotes targets on
2322
+ * reviewed effort corrections (the cascade's thinking-axis gate), but compat
2323
+ * may only be repaired where the matching contract opted in with
2324
+ * `thinking-upgrade-neutral`; everywhere else a spec that reports no reasoning
2325
+ * stays the authoritative capability surface.
2326
+ */
2327
+ function compatReasoning(spec, axes) {
2328
+ if (spec.reasoning) return true;
2329
+ return axes.reasoning && readRuleThinking(axes).upgradeNeutral === true;
2330
+ }
2331
+ /** Identity-derived `requiresEffort` default (mandatory-reasoning lineages). */
2332
+ function impliesMandatoryReasoning(facts, modelId) {
2333
+ if (facts.identity.thinkingVariant) return true;
2334
+ if (stripThinkingVariantSuffix(modelId) !== void 0) return true;
2335
+ return false;
2336
+ }
2337
+ function isQwenTemplateReasoningEffortCompat(compat) {
2338
+ return compat !== void 0 && "qwenTemplateReasoningEffort" in compat && compat.qwenTemplateReasoningEffort === true;
2339
+ }
2340
+ function resolveThinkingPolicy(spec, facts, axes, compat) {
2341
+ const rule = readRuleThinking(axes);
2342
+ const explicitThinking = spec.thinking !== void 0 && Array.isArray(spec.thinking.efforts) && spec.thinking.efforts.length > 0 ? spec.thinking : void 0;
2343
+ const unverified = !compatReasoning(spec, axes);
2344
+ if (unverified && (explicitThinking !== void 0 || facts.identity.class !== "unknown" || rule.unverified !== true)) return;
2345
+ if (omitsWireReasoningEffort(spec.api, compat)) return void 0;
2346
+ if (explicitThinking !== void 0) return fillExplicitThinking(spec, facts, compat, explicitThinking, rule);
2347
+ if (compat !== void 0 && "trustExplicitThinkingOnly" in compat && compat.trustExplicitThinkingOnly === true) return;
2348
+ if (rule.efforts?.length === 0) return void 0;
2349
+ const config = {
2350
+ mode: rule.mode ?? defaultThinkingMode(spec, facts),
2351
+ efforts: rule.efforts ?? fallbackEfforts(spec, compat)
2352
+ };
2353
+ if (config.efforts.length === 0) throw new Error(`Model ${spec.provider}/${spec.id} resolved to an empty thinking range`);
2354
+ const effortMap = mergeEffortMap(spec, rule.effortMap, compat, config.efforts);
2355
+ if (effortMap !== void 0) config.effortMap = effortMap;
2356
+ if (unverified) {
2357
+ config.unverified = true;
2358
+ return config;
2359
+ }
2360
+ if (rule.defaultLevel !== void 0) config.defaultLevel = rule.defaultLevel;
2361
+ if (rule.effortBudgets !== void 0) config.effortBudgets = rule.effortBudgets;
2362
+ if (rule.supportsDisplay ?? defaultSupportsDisplay(spec, facts)) config.supportsDisplay = true;
2363
+ if (rule.prefixBinding) config.prefixBinding = true;
2364
+ if (rule.requiresEffort ?? (impliesMandatoryReasoning(facts, spec.id) || isQwenTemplateReasoningEffortCompat(compat))) config.requiresEffort = true;
2365
+ if (rule.suppressWhenOff) config.suppressWhenOff = true;
2366
+ return config;
2367
+ }
2368
+ /**
2369
+ * Displayable-thinking default: an api-conditioned lineage fact (Anthropic
2370
+ * wire dialects streaming adaptive Claude 4.7+ thinking) that KDL cannot
2371
+ * express — cascade selectors have no api dimension. `thinking-supports-display`
2372
+ * rules override per deployment.
2373
+ */
2374
+ function defaultSupportsDisplay(spec, facts) {
2375
+ return (spec.api === "anthropic-messages" || spec.api === "bedrock-converse-stream") && facts.anthropicAdaptiveGenAtLeast("4.7");
2376
+ }
2377
+ function mergeEffortMap(spec, ruleMap, compat, efforts) {
2378
+ const detected = (spec.api === "openai-completions" || spec.api === "openrouter") && modelMatchesHost({
2379
+ provider: spec.provider,
2380
+ baseUrl: spec.baseUrl ?? ""
2381
+ }, "fireworks") ? FIREWORKS_THINKING_EFFORT_MAP : void 0;
2382
+ const configured = readCompatEffortMap(compat);
2383
+ if (detected === void 0 && ruleMap === void 0 && configured === void 0) return void 0;
2384
+ return filterEffortMap({
2385
+ ...detected,
2386
+ ...ruleMap,
2387
+ ...configured
2388
+ }, efforts);
2389
+ }
2390
+ /**
2391
+ * Backfill missing wire/default fields onto explicit thinking metadata.
2392
+ * Explicit spec thinking is layer 4 of the resolution order: its ladder and
2393
+ * every explicitly-set field always win; only absent fields are filled from
2394
+ * the rules and identity-derived defaults.
2395
+ */
2396
+ function fillExplicitThinking(spec, facts, compat, thinking, rule) {
2397
+ const effortMap = thinking.effortMap === void 0 ? mergeEffortMap(spec, rule.effortMap, compat, thinking.efforts) : void 0;
2398
+ const needsDisplay = thinking.supportsDisplay === void 0 && (rule.supportsDisplay ?? defaultSupportsDisplay(spec, facts));
2399
+ const needsRequiresEffort = thinking.requiresEffort === void 0 && (rule.requiresEffort ?? (impliesMandatoryReasoning(facts, spec.id) || isQwenTemplateReasoningEffortCompat(compat)));
2400
+ const needsDefaultLevel = thinking.defaultLevel === void 0 && rule.defaultLevel !== void 0;
2401
+ const needsPrefixBinding = thinking.prefixBinding === void 0 && rule.prefixBinding === true;
2402
+ const needsEffortBudgets = thinking.effortBudgets === void 0 && rule.effortBudgets !== void 0;
2403
+ if (effortMap === void 0 && !needsDisplay && !needsRequiresEffort && !needsDefaultLevel && !needsPrefixBinding && !needsEffortBudgets) return thinking;
2404
+ const filled = { ...thinking };
2405
+ if (effortMap !== void 0) filled.effortMap = effortMap;
2406
+ if (needsDisplay) filled.supportsDisplay = true;
2407
+ if (needsDefaultLevel && rule.defaultLevel !== void 0) filled.defaultLevel = rule.defaultLevel;
2408
+ if (needsRequiresEffort) filled.requiresEffort = true;
2409
+ if (needsPrefixBinding) filled.prefixBinding = true;
2410
+ if (needsEffortBudgets) filled.effortBudgets = rule.effortBudgets;
2411
+ return filled;
2412
+ }
2413
+ function buildResolveTarget(spec, identity, providerType = spec.providerType ?? spec.provider) {
2414
+ const target = {
2415
+ provider: providerType,
2416
+ api: spec.api,
2417
+ class: identity.class,
2418
+ model: policyModelId(spec),
2419
+ reasoning: Boolean(spec.reasoning)
2420
+ };
2421
+ if (identity.family !== void 0) target.family = identity.family;
2422
+ if (identity.revision !== void 0) target.revision = identity.revision;
2423
+ return target;
2424
+ }
2425
+ function specUsesApi(spec, api) {
2426
+ return spec.api === api;
2427
+ }
2428
+ /**
2429
+ * Catalog-data axis assignments for one model spec — the `catalog` field of
2430
+ * {@link resolveModelPolicy} without resolving the compat and thinking
2431
+ * policies, which dominate its cost on catalog-wide scans.
2432
+ */
2433
+ function resolveCatalogAxes(spec) {
2434
+ return resolveCascade(buildResolveTarget(spec, resolveIdentity(spec))).catalog;
2435
+ }
2436
+ function resolveModelPolicy(input, route) {
2437
+ const spec = withoutUnverifiedThinking(input);
2438
+ const identity = resolveIdentity(spec);
2439
+ const facts = new IdentityFacts(identity);
2440
+ const target = buildResolveTarget(spec, identity);
2441
+ target.upstream = route?.upstream;
2442
+ const axes = resolveCascade(target);
2443
+ let compat;
2444
+ if (specUsesApi(spec, "openrouter")) {
2445
+ const chat = resolveOpenAICompletionsPolicy(spec, facts, axes);
2446
+ const responses = resolveOpenAIResponsesPolicy(spec, facts, axes, "openrouter");
2447
+ compat = {
2448
+ ...chat,
2449
+ ...pickResponsesOnly(responses)
2450
+ };
2451
+ } else if (specUsesApi(spec, "openai-completions")) compat = resolveOpenAICompletionsPolicy(spec, facts, axes);
2452
+ else if (specUsesApi(spec, "openai-responses") || specUsesApi(spec, "azure-openai-responses") || specUsesApi(spec, "openai-codex-responses")) compat = resolveOpenAIResponsesPolicy(spec, facts, axes, spec.api);
2453
+ else if (specUsesApi(spec, "anthropic-messages")) compat = resolveAnthropicPolicy(spec, facts, axes);
2454
+ else if (specUsesApi(spec, "bedrock-converse-stream")) compat = resolveBedrockPolicy(spec, axes);
2455
+ else if (specUsesApi(spec, "ollama-chat")) compat = resolveOllamaPolicy(spec, axes);
2456
+ else if (specUsesApi(spec, "devin-agent")) compat = resolveDevinPolicy(spec, axes);
2457
+ else if (specUsesApi(spec, "google-generative-ai") || specUsesApi(spec, "google-vertex") || specUsesApi(spec, "google-gemini-cli")) compat = resolveGooglePolicy(spec, axes);
2458
+ else compat = void 0;
2459
+ return {
2460
+ identity,
2461
+ compat,
2462
+ thinking: resolveThinkingPolicy(spec, facts, axes, compat),
2463
+ catalog: axes.catalog,
2464
+ request: resolveRequestPolicy(axes)
2465
+ };
2466
+ }
2467
+ /**
2468
+ * Whether reviewed rules know THIS model's effort ladder, as opposed to it
2469
+ * inheriting a provider-wide default or {@link resolveThinkingPolicy} falling
2470
+ * through to the neutral wire ladder.
2471
+ *
2472
+ * Discovery uses this to tell "omp knows this model's tiers" apart from "omp
2473
+ * is guessing them", so catalog-published tiers can correct the guess without
2474
+ * ever overriding reviewed knowledge.
2475
+ */
2476
+ function hasModelScopedEffortLadder(spec) {
2477
+ return hasModelScopedEffortsRule(buildResolveTarget(spec, resolveIdentity(spec)));
2478
+ }
2479
+ //#endregion
2480
+ //#region node_modules/.pnpm/@oh-my-pi+pi-catalog@18.12.6/node_modules/@oh-my-pi/pi-catalog/src/identity/id.ts
2481
+ const LEADING_BRACKETED_AFFIX_PATTERN = /^(?:\s*(?:\[|【)[^\]】]+(?:\]|】)\s*)+/u;
2482
+ const TRAILING_BRACKETED_AFFIX_PATTERN = /(?:\s*(?:\[|【)[^\]】]+(?:\]|】)\s*)+$/u;
2483
+ /** Strip a provider namespace prefix (`openai/gpt-5.4` → `gpt-5.4`). */
2484
+ const bareModelIdCache = /* @__PURE__ */ new Map();
2485
+ function bareModelId(modelId) {
2486
+ const cached = bareModelIdCache.get(modelId);
2487
+ if (cached !== void 0) return cached;
2488
+ const separator = modelId.lastIndexOf("/");
2489
+ const result = separator === -1 ? modelId : modelId.slice(separator + 1);
2490
+ bareModelIdCache.set(modelId, result);
2491
+ return result;
2492
+ }
2493
+ const MODEL_ID_SEGMENT_PATTERN = /[a-z0-9.:-]+/g;
2494
+ const MODEL_FAMILY_PREFIX_PATTERN = /^(claude|gemini|gpt|grok|glm|qwen|deepseek|kimi|mimo|doubao|ernie|gpt-oss|gemma|minimax|step|command|jamba|llama|o[1345])/i;
2495
+ function normalizeModelIdWhitespace(value) {
2496
+ return value.trim().replace(/\s+/g, " ");
2497
+ }
2498
+ /** Ordering for model-like segments: longest first, ties broken lexicographically. */
2499
+ function compareSegmentPreference(left, right) {
2500
+ return left.length !== right.length ? right.length - left.length : left.localeCompare(right);
2501
+ }
2502
+ function getModelLikeIdSegments(modelId) {
2503
+ const matches = normalizeModelIdWhitespace(modelId).toLowerCase().match(MODEL_ID_SEGMENT_PATTERN);
2504
+ if (!matches) return [];
2505
+ const segments = /* @__PURE__ */ new Set();
2506
+ for (const segment of matches) if (MODEL_FAMILY_PREFIX_PATTERN.test(segment) && /\d/.test(segment)) segments.add(segment);
2507
+ return [...segments].sort(compareSegmentPreference);
2508
+ }
2509
+ function getLongestModelLikeIdSegment(modelId) {
2510
+ const matches = normalizeModelIdWhitespace(modelId).toLowerCase().match(MODEL_ID_SEGMENT_PATTERN);
2511
+ if (!matches) return void 0;
2512
+ let best;
2513
+ for (const segment of matches) if (MODEL_FAMILY_PREFIX_PATTERN.test(segment) && /\d/.test(segment) && (best === void 0 || compareSegmentPreference(segment, best) < 0)) best = segment;
2514
+ return best;
2515
+ }
2516
+ function hasBracketAffixMarker(value) {
2517
+ for (let index = 0; index < value.length; index++) {
2518
+ const code = value.charCodeAt(index);
2519
+ if (code === 91 || code === 93 || code === 12304 || code === 12305) return true;
2520
+ }
2521
+ return false;
2522
+ }
2523
+ /**
2524
+ * Strip reseller / wrapper tags that are injected as bracketed affixes around an
2525
+ * upstream model id, e.g.
2526
+ * "[Kiro] claude-opus-4-8" -> "claude-opus-4-8"
2527
+ * "[gcli转] gemini-3.1-pro-preview [假流]" -> "gemini-3.1-pro-preview"
2528
+ *
2529
+ * Candidates are returned most-stripped first: both ends, then leading-only, then trailing-only.
2530
+ */
2531
+ function getBracketStrippedModelIdCandidates(modelId) {
2532
+ if (!hasBracketAffixMarker(modelId)) return [];
2533
+ const normalized = normalizeModelIdWhitespace(modelId);
2534
+ if (!normalized) return [];
2535
+ const strippedLeading = normalized.replace(LEADING_BRACKETED_AFFIX_PATTERN, "");
2536
+ const withoutLeading = normalizeModelIdWhitespace(strippedLeading);
2537
+ const withoutTrailing = normalizeModelIdWhitespace(normalized.replace(TRAILING_BRACKETED_AFFIX_PATTERN, ""));
2538
+ const withoutBoth = normalizeModelIdWhitespace(strippedLeading.replace(TRAILING_BRACKETED_AFFIX_PATTERN, ""));
2539
+ const candidates = /* @__PURE__ */ new Set();
2540
+ for (const candidate of [
2541
+ withoutBoth,
2542
+ withoutLeading,
2543
+ withoutTrailing
2544
+ ]) if (candidate && candidate !== normalized) candidates.add(candidate);
2545
+ return [...candidates];
2546
+ }
2547
+ //#endregion
2548
+ export { withoutUnverifiedThinking as A, applyCodexResidencyHeader as C, mapEffortToAnthropicAdaptiveEffort as D, getSupportedEfforts as E, resolveVertexEndpointHost as F, Effort as I, THINKING_EFFORTS as L, isBedrockRouteUrl as M, isVertexRawPredictUrl as N, requireSupportedEffort as O, modelMatchesHost as P, OPENAI_HEADER_VALUES as S, getCodexAccountId as T, isBedrockAnthropicRoute as _, hasModelScopedEffortLadder as a, CODEX_CLIENT_VERSION as b, FACTORY_DROID_WIRES as c, factoryDroidModelCacheProviderId as d, factoryDroidWireBaseUrl as f, isAnthropicSigningProxyUrl as g, MODEL_KINDS as h, getModelLikeIdSegments as i, hostMatchesUrl as j, resolveWireModelId as k, factoryDroidApiBaseUrl as l, KIND_API_KINDS as m, getBracketStrippedModelIdCandidates as n, resolveCatalogAxes as o, resolveFactoryDroidInferenceRegion as p, getLongestModelLikeIdSegment as r, resolveModelPolicy as s, bareModelId as t, factoryDroidClientHeaders as u, isOfficialAnthropicApiUrl as v, codexRoutingHint as w, OPENAI_HEADERS as x, CODEX_BASE_URL as y };