@explyt/ai-agent 0.1.5 → 0.2.1

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 (40) hide show
  1. package/README.md +3 -3
  2. package/THIRD-PARTY-NOTICES.md +41 -10
  3. package/agent-docs/README.md +1 -1
  4. package/agent-docs/settings.md +14 -2
  5. package/dist/cli/engine.js +16 -12
  6. package/dist/cli/index.js +2 -2
  7. package/dist/cli/update.js +7 -3
  8. package/dist/extensions/ask-user-question.js +1 -1
  9. package/dist/extensions/bash.js +1 -1
  10. package/dist/extensions/custom-provider.js +1 -1
  11. package/dist/extensions/hello.js +1 -1
  12. package/dist/extensions/identity.js +1 -1
  13. package/dist/extensions/mcp.js +1 -1
  14. package/dist/extensions/misc-hacks.js +1 -1
  15. package/dist/extensions/policy.js +1 -1
  16. package/dist/extensions/rules.js +1 -1
  17. package/dist/extensions/session-title.js +1 -1
  18. package/dist/extensions/skills.js +1 -1
  19. package/dist/extensions/subagents.js +1 -0
  20. package/dist/extensions/tui.js +1 -1
  21. package/dist/extensions/update-notice.js +1 -1
  22. package/dist/extensions/web-access.js +1 -1
  23. package/dist/extensions/write.js +1 -0
  24. package/dist/mcp-adapter.js +4 -4
  25. package/dist/rpiv-ask-user-question/{chunk-GAM3ZAHN.js → chunk-JNDW3P3A.js} +2 -2
  26. package/dist/rpiv-ask-user-question/index.js +3 -3
  27. package/dist/vendor/model-probe/rules.json +102 -0
  28. package/dist/vendor/model-probe/src/index.js +983 -0
  29. package/dist/vendor/model-probe/src/opencode-models-snapshot.js +8 -0
  30. package/dist/vendor/model-probe/src/opencode-models.js +6 -0
  31. package/dist/vendor/pi-ai-compat.js +2 -0
  32. package/dist/vendor/pi-coding-agent.js +159 -0
  33. package/dist/vendor/pi-web-access-deps/modelcontextprotocol__sdk__client__index.js.js +9 -0
  34. package/dist/vendor/pi-web-access-deps/modelcontextprotocol__sdk__client__streamableHttp.js.js +9 -0
  35. package/dist/vendor/pi-web-access.js +24958 -0
  36. package/dist/vendor/typebox/chunk-6XHASRAZ.js +4819 -0
  37. package/dist/vendor/typebox/index.js +703 -0
  38. package/dist/vendor/typebox/value.js +3736 -0
  39. package/package.json +12 -5
  40. package/dist/extensions/subagents-package.js +0 -46
@@ -0,0 +1,983 @@
1
+ /*
2
+ * model-probe@0.6.0 -- MIT License, Copyright (c) 2025 ratatulieoi, Copyright (c) 2026 real-wudaoshi.
3
+ * Compiled unobfuscated and unmodified by Explyt AI Agent. Full license text: THIRD-PARTY-NOTICES.md.
4
+ */
5
+
6
+ // release/node_modules/model-probe/src/known-models.ts
7
+ import { existsSync, readFileSync } from "node:fs";
8
+ import { homedir } from "node:os";
9
+ import { dirname, join } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ var BUILTIN_RULES_PATH = join(dirname(fileURLToPath(import.meta.url)), "..", "rules.json");
12
+ var programmaticRules = [];
13
+ var cache = null;
14
+ function registerKnownModelRules(rules) {
15
+ programmaticRules.push(...rules);
16
+ cache = null;
17
+ }
18
+ function reloadKnownModelRules() {
19
+ cache = null;
20
+ }
21
+ function compileRules(raw, source) {
22
+ if (!Array.isArray(raw)) return [];
23
+ const out = [];
24
+ for (const entry of raw) {
25
+ if (!entry || typeof entry !== "object" || typeof entry.pattern !== "string") continue;
26
+ try {
27
+ out.push({
28
+ regex: new RegExp(entry.pattern, typeof entry.flags === "string" ? entry.flags : "i"),
29
+ contextWindow: typeof entry.contextWindow === "number" ? entry.contextWindow : void 0,
30
+ maxTokens: typeof entry.maxTokens === "number" ? entry.maxTokens : void 0,
31
+ image: typeof entry.image === "boolean" ? entry.image : void 0,
32
+ video: typeof entry.video === "boolean" ? entry.video : void 0,
33
+ reasoning: typeof entry.reasoning === "boolean" ? entry.reasoning : void 0
34
+ });
35
+ } catch {
36
+ console.warn(`model-probe: skipping invalid rule in ${source}: ${entry.pattern}`);
37
+ }
38
+ }
39
+ return out;
40
+ }
41
+ function readRulesFile(path) {
42
+ try {
43
+ return compileRules(JSON.parse(readFileSync(path, "utf8")), path);
44
+ } catch {
45
+ return [];
46
+ }
47
+ }
48
+ function userRulesPath() {
49
+ return process.env.MODEL_PROBE_RULES || join(homedir(), ".model-probe-rules.json");
50
+ }
51
+ function loadRules() {
52
+ if (cache) return cache;
53
+ const rules = [...compileRules(programmaticRules, "registerKnownModelRules")];
54
+ const userPath = userRulesPath();
55
+ if (existsSync(userPath)) rules.push(...readRulesFile(userPath));
56
+ rules.push(...readRulesFile(BUILTIN_RULES_PATH));
57
+ cache = rules;
58
+ return rules;
59
+ }
60
+ function normalizeModelIdCandidates(modelId) {
61
+ const candidates = [];
62
+ const push = (v) => {
63
+ if (v && !candidates.includes(v)) candidates.push(v);
64
+ };
65
+ const raw = modelId.trim();
66
+ push(raw);
67
+ const lower = raw.toLowerCase();
68
+ push(lower);
69
+ const withoutAt = lower.split("@")[0];
70
+ push(withoutAt);
71
+ const withoutSuffix = withoutAt.replace(/\[1m\]$/i, "");
72
+ push(withoutSuffix);
73
+ push(withoutSuffix.replace(/-20\d{6}$/, ""));
74
+ push(withoutSuffix.replace(/-\d{2,9}$/, ""));
75
+ push(
76
+ withoutSuffix.replace(
77
+ /-(?:latest|recent|free|preview|stable|thinking|reasoning|turbo|hi|highspeed|dev|beta|auto|labs)$/,
78
+ ""
79
+ )
80
+ );
81
+ const lastSegment = withoutSuffix.split("/").pop() ?? "";
82
+ if (lastSegment && lastSegment !== withoutSuffix) {
83
+ push(lastSegment);
84
+ push(lastSegment.replace(/-20\d{6}$/, ""));
85
+ }
86
+ return candidates;
87
+ }
88
+ function matchKnownModelRule(modelId) {
89
+ const info = {};
90
+ let matched = false;
91
+ for (const candidate of normalizeModelIdCandidates(modelId)) {
92
+ for (const rule of loadRules()) {
93
+ if (!rule.regex.test(candidate)) continue;
94
+ matched = true;
95
+ if (info.contextWindow === void 0 && rule.contextWindow !== void 0) info.contextWindow = rule.contextWindow;
96
+ if (info.maxTokens === void 0 && rule.maxTokens !== void 0) info.maxTokens = rule.maxTokens;
97
+ if (info.image === void 0 && rule.image !== void 0) info.image = rule.image;
98
+ if (info.video === void 0 && rule.video !== void 0) info.video = rule.video;
99
+ if (info.reasoning === void 0 && rule.reasoning !== void 0) info.reasoning = rule.reasoning;
100
+ }
101
+ if (info.contextWindow !== void 0 && info.maxTokens !== void 0 && info.image !== void 0 && info.video !== void 0 && info.reasoning !== void 0) {
102
+ return info;
103
+ }
104
+ }
105
+ return matched ? info : void 0;
106
+ }
107
+ function applyKnownModelFallback(modelId, info) {
108
+ const known = matchKnownModelRule(modelId);
109
+ if (!known) return info;
110
+ const filled = {};
111
+ const inferredFields = [];
112
+ if (info?.contextWindow === void 0 && known.contextWindow !== void 0) {
113
+ filled.contextWindow = known.contextWindow;
114
+ inferredFields.push("contextWindow");
115
+ }
116
+ if (info?.maxTokens === void 0 && known.maxTokens !== void 0) {
117
+ filled.maxTokens = known.maxTokens;
118
+ inferredFields.push("maxTokens");
119
+ }
120
+ if (info?.image === void 0 && known.image !== void 0) {
121
+ filled.image = known.image;
122
+ inferredFields.push("image");
123
+ }
124
+ if (info?.video === void 0 && known.video !== void 0) {
125
+ filled.video = known.video;
126
+ inferredFields.push("video");
127
+ }
128
+ if (info?.reasoning === void 0 && known.reasoning !== void 0) {
129
+ filled.reasoning = known.reasoning;
130
+ inferredFields.push("reasoning");
131
+ }
132
+ if (inferredFields.length === 0) return info;
133
+ return { ...info ?? {}, ...filled, inferred: true, inferredFields };
134
+ }
135
+
136
+ // release/node_modules/model-probe/src/types.ts
137
+ var FULL_PROFILE = {
138
+ modelInfo: true,
139
+ modelGroupInfo: true,
140
+ publicCatalog: true,
141
+ perModelDetails: true,
142
+ modelsDev: true
143
+ };
144
+ var PROBE_CONCURRENCY = 4;
145
+ var PROBE_TIMEOUT_MS = 4e3;
146
+
147
+ // release/node_modules/model-probe/src/url.ts
148
+ function dedupe(values) {
149
+ return Array.from(new Set(values));
150
+ }
151
+ function buildProbeUrl(baseUrl) {
152
+ const withSlash = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
153
+ return new URL("models", withSlash).toString();
154
+ }
155
+ function getPath(obj, path) {
156
+ let current = obj;
157
+ for (const key of path.split(".")) {
158
+ if (!current || typeof current !== "object") return void 0;
159
+ current = current[key];
160
+ }
161
+ return current;
162
+ }
163
+ function firstFiniteNumber(obj, ...paths) {
164
+ for (const path of paths) {
165
+ const value = getPath(obj, path);
166
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
167
+ }
168
+ return void 0;
169
+ }
170
+
171
+ // release/node_modules/model-probe/src/probe.ts
172
+ var ProbeRetryable = class extends Error {
173
+ };
174
+ function isLocalHost(hostname) {
175
+ const lower = hostname.toLowerCase();
176
+ return lower === "localhost" || lower.endsWith(".local") || lower.startsWith("127.") || lower.startsWith("0.0.0.0") || lower.startsWith("10.") || lower.startsWith("192.168.") || /^172\.(1[6-9]|2\d|3[01])\./.test(lower) || lower === "[::1]";
177
+ }
178
+ function probeBaseVariants(baseUrl) {
179
+ const trimmed = baseUrl.replace(/\/+$/, "");
180
+ try {
181
+ const url = new URL(trimmed);
182
+ let pathVariant = null;
183
+ if (url.pathname.endsWith("/v1")) {
184
+ url.pathname = url.pathname.slice(0, -3) || "/";
185
+ pathVariant = url.toString().replace(/\/+$/, "");
186
+ } else if (url.pathname === "" || url.pathname === "/") {
187
+ url.pathname = "/v1";
188
+ pathVariant = url.toString().replace(/\/+$/, "");
189
+ }
190
+ const variants = [trimmed, ...pathVariant ? [pathVariant] : []];
191
+ if (url.protocol === "http:" && !isLocalHost(url.hostname)) {
192
+ for (const v of [...variants]) {
193
+ const secure = new URL(v);
194
+ secure.protocol = "https:";
195
+ variants.push(secure.toString().replace(/\/+$/, ""));
196
+ }
197
+ }
198
+ return dedupe(variants);
199
+ } catch {
200
+ }
201
+ return [trimmed];
202
+ }
203
+ async function fetchModelsList(baseUrl, headers) {
204
+ const probeUrl = buildProbeUrl(baseUrl);
205
+ const controller = new AbortController();
206
+ const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
207
+ let response;
208
+ try {
209
+ response = await fetch(probeUrl, { headers, signal: controller.signal });
210
+ } catch (error) {
211
+ if (controller.signal.aborted) {
212
+ throw new ProbeRetryable(`Probe timed out after ${PROBE_TIMEOUT_MS / 1e3}s: ${probeUrl}`);
213
+ }
214
+ throw new ProbeRetryable(error instanceof Error ? error.message : String(error));
215
+ } finally {
216
+ clearTimeout(timer);
217
+ }
218
+ if (response.status === 404) {
219
+ throw new ProbeRetryable(`Probe failed (404 Not Found): ${probeUrl}`);
220
+ }
221
+ if (!response.ok) {
222
+ const body = await response.text().catch(() => "");
223
+ throw new Error(`Probe failed (${response.status} ${response.statusText})${body ? `: ${body.slice(0, 200)}` : ""}`);
224
+ }
225
+ try {
226
+ return await response.json();
227
+ } catch {
228
+ throw new ProbeRetryable(`Probe got a non-JSON response (a web page, not an API): ${probeUrl}`);
229
+ }
230
+ }
231
+ async function probeModels(baseUrl, apiKey) {
232
+ const headers = {
233
+ accept: "application/json",
234
+ "accept-encoding": "identity"
235
+ };
236
+ if (apiKey) {
237
+ headers.authorization = `Bearer ${apiKey}`;
238
+ headers["x-goog-api-key"] = apiKey;
239
+ }
240
+ const variants = probeBaseVariants(baseUrl);
241
+ let json;
242
+ let resolvedBaseUrl = variants[0];
243
+ for (let i = 0; i < variants.length; i++) {
244
+ try {
245
+ json = await fetchModelsList(variants[i], headers);
246
+ resolvedBaseUrl = variants[i];
247
+ break;
248
+ } catch (error) {
249
+ if (!(error instanceof ProbeRetryable) || i === variants.length - 1) throw error;
250
+ }
251
+ }
252
+ const rawModels = Array.isArray(json) ? json : Array.isArray(json?.data) ? json.data : Array.isArray(json?.models) ? json.models : [];
253
+ const infoById = /* @__PURE__ */ new Map();
254
+ const ids = dedupe(
255
+ rawModels.map((item) => {
256
+ const rawId = typeof item?.id === "string" ? item.id : typeof item?.name === "string" ? item.name : "";
257
+ if (!rawId.trim()) return "";
258
+ const id = rawId.trim().replace(/^models\//, "");
259
+ const info = parseModelListItem(item);
260
+ if (info) infoById.set(id, info);
261
+ return id;
262
+ }).filter(Boolean)
263
+ ).sort((a, b) => a.localeCompare(b));
264
+ return { ids, infoById, baseUrl: resolvedBaseUrl };
265
+ }
266
+ var API_FALLBACK_LIMITS = {
267
+ "anthropic-messages": { contextWindow: 2e5, maxTokens: 32e3 },
268
+ "google-generative-ai": { contextWindow: 1048576, maxTokens: 65536 },
269
+ "openai-completions": { contextWindow: 258e3, maxTokens: 32e3 },
270
+ "openai-responses": { contextWindow: 258e3, maxTokens: 32e3 }
271
+ };
272
+ var MAX_OUTPUT_TOKEN_CAP = 32e3;
273
+ function normalizeModelLimits(contextWindow, maxTokens) {
274
+ if (contextWindow <= 0 || maxTokens < contextWindow) return { contextWindow, maxTokens };
275
+ return {
276
+ contextWindow,
277
+ maxTokens: Math.min(MAX_OUTPUT_TOKEN_CAP, Math.max(1, Math.floor(contextWindow / 4)))
278
+ };
279
+ }
280
+ var MODEL_INFO_DEFAULTS = { image: false, video: false, reasoning: true };
281
+ function applyModelDefaults(info) {
282
+ const out = { ...info ?? {} };
283
+ const defaulted = [...info?.defaultedFields ?? []];
284
+ if (out.image === void 0) {
285
+ out.image = MODEL_INFO_DEFAULTS.image;
286
+ defaulted.push("image");
287
+ }
288
+ if (out.video === void 0) {
289
+ out.video = MODEL_INFO_DEFAULTS.video;
290
+ defaulted.push("video");
291
+ }
292
+ if (out.reasoning === void 0) {
293
+ out.reasoning = MODEL_INFO_DEFAULTS.reasoning;
294
+ defaulted.push("reasoning");
295
+ }
296
+ if (defaulted.length > 0) out.defaultedFields = defaulted;
297
+ return out;
298
+ }
299
+ function probeInfoSummary(info) {
300
+ if (!info) return [];
301
+ const defaulted = new Set(info.defaultedFields ?? []);
302
+ const parts = [];
303
+ if (info.contextWindow !== void 0 && !defaulted.has("contextWindow")) parts.push("context");
304
+ if (info.maxTokens !== void 0 && !defaulted.has("maxTokens")) parts.push("maxTokens");
305
+ if (info.reasoning !== void 0 && !defaulted.has("reasoning")) parts.push("reasoning");
306
+ if (info.image !== void 0 && !defaulted.has("image")) parts.push("image");
307
+ if (info.video !== void 0 && !defaulted.has("video")) parts.push("video");
308
+ return parts;
309
+ }
310
+ function hasProbeInfo(info) {
311
+ if (!info) return false;
312
+ return probeInfoSummary(info).length > 0 || info.endpointTypes !== void 0 && info.endpointTypes.length > 0;
313
+ }
314
+ function describeProbeInfo(info) {
315
+ if (!info) return void 0;
316
+ const inferred = new Set(info.inferredFields ?? []);
317
+ const fromModelsDev = new Set(info.modelsDevFields ?? []);
318
+ const defaulted = new Set(info.defaultedFields ?? []);
319
+ const tag = (field) => inferred.has(field) ? " [local rules]" : fromModelsDev.has(field) ? " [models.dev]" : "";
320
+ const parts = [];
321
+ if (info.contextWindow !== void 0 && !defaulted.has("contextWindow")) parts.push(`ctx ${info.contextWindow}${tag("contextWindow")}`);
322
+ if (info.maxTokens !== void 0 && !defaulted.has("maxTokens")) parts.push(`max-out ${info.maxTokens}${tag("maxTokens")}`);
323
+ if (info.image === true) parts.push(`image${tag("image")}`);
324
+ if (info.video === true) parts.push(`video${tag("video")}`);
325
+ if (info.reasoning === false) parts.push(`no reasoning${tag("reasoning")}`);
326
+ else if (info.reasoning === true && info.alwaysThinking) parts.push(`reasoning (always on)${tag("reasoning")}`);
327
+ if (info.endpointTypes && info.endpointTypes.length > 0) parts.push(info.endpointTypes.join("/"));
328
+ return parts.length > 0 ? parts.join(" \u2022 ") : void 0;
329
+ }
330
+ function parseGatewayMetaFields(source, info) {
331
+ const meta = source?.meta;
332
+ if (!meta || typeof meta !== "object") return;
333
+ if (info.contextWindow === void 0) {
334
+ const contextWindow = firstFiniteNumber(meta, "context_window", "max_input_tokens");
335
+ if (contextWindow !== void 0) info.contextWindow = contextWindow;
336
+ }
337
+ if (info.maxTokens === void 0) {
338
+ const maxTokens = firstFiniteNumber(meta, "max_output_tokens", "max_tokens");
339
+ if (maxTokens !== void 0) info.maxTokens = maxTokens;
340
+ }
341
+ const capabilities = meta.capabilities;
342
+ if (capabilities && typeof capabilities === "object") {
343
+ if (info.image === void 0 && typeof capabilities.vision === "boolean") info.image = capabilities.vision;
344
+ if (info.reasoning === void 0 && typeof capabilities.reasoning === "boolean") info.reasoning = capabilities.reasoning;
345
+ if (info.reasoning === void 0 && typeof capabilities.thinking === "boolean") info.reasoning = capabilities.thinking;
346
+ }
347
+ if (info.image === void 0 && typeof meta.supports_vision === "boolean") info.image = meta.supports_vision;
348
+ if (info.reasoning === void 0 && typeof meta.supports_reasoning === "boolean") info.reasoning = meta.supports_reasoning;
349
+ }
350
+ function parseModelListItem(item) {
351
+ if (!item || typeof item !== "object") return void 0;
352
+ const info = {};
353
+ const contextWindow = firstFiniteNumber(item, "context_length", "context_window", "max_input_tokens", "inputTokenLimit");
354
+ if (contextWindow !== void 0) info.contextWindow = contextWindow;
355
+ const maxTokens = firstFiniteNumber(item, "max_output_tokens", "max_completion_tokens", "outputTokenLimit");
356
+ if (maxTokens !== void 0) info.maxTokens = maxTokens;
357
+ else if (typeof item.top_provider === "object" && item.top_provider !== null) {
358
+ const top = firstFiniteNumber(item.top_provider, "max_completion_tokens");
359
+ if (top !== void 0) info.maxTokens = top;
360
+ }
361
+ if (typeof item.reasoning === "boolean") info.reasoning = item.reasoning;
362
+ const modalities = Array.isArray(item.architecture?.input_modalities) ? item.architecture.input_modalities : Array.isArray(item.modalities) ? item.modalities : void 0;
363
+ if (modalities) {
364
+ info.image = modalities.includes("image");
365
+ info.video = modalities.includes("video");
366
+ }
367
+ if (Array.isArray(item.capabilities)) {
368
+ if (info.reasoning === void 0) info.reasoning = item.capabilities.includes("thinking") || item.capabilities.includes("reasoning");
369
+ if (info.image === void 0) info.image = item.capabilities.includes("vision");
370
+ }
371
+ if (Array.isArray(item.supported_endpoint_types)) {
372
+ const types = item.supported_endpoint_types.filter((t) => typeof t === "string");
373
+ if (types.length > 0) info.endpointTypes = types;
374
+ }
375
+ parseGatewayMetaFields(item, info);
376
+ return hasProbeInfo(info) ? info : void 0;
377
+ }
378
+ function parseOpenAIModelDetail(json) {
379
+ if (!json || typeof json !== "object") return void 0;
380
+ const info = {};
381
+ const contextWindow = firstFiniteNumber(json, "context_window", "inputTokenLimit");
382
+ if (contextWindow !== void 0) info.contextWindow = contextWindow;
383
+ const maxTokens = firstFiniteNumber(json, "max_output_tokens", "outputTokenLimit");
384
+ if (maxTokens !== void 0) info.maxTokens = maxTokens;
385
+ const capabilities = json.capabilities;
386
+ if (capabilities && typeof capabilities === "object") {
387
+ if (capabilities.vision && typeof capabilities.vision === "object" && typeof capabilities.vision.supported === "boolean") {
388
+ info.image = capabilities.vision.supported;
389
+ }
390
+ const reasoning = capabilities.reasoning;
391
+ if (reasoning && typeof reasoning === "object") {
392
+ const type = typeof reasoning.type === "string" ? reasoning.type : "";
393
+ if (type === "none") {
394
+ info.reasoning = false;
395
+ } else if (type === "minimal") {
396
+ info.reasoning = true;
397
+ info.alwaysThinking = true;
398
+ } else if (type === "effort") {
399
+ info.reasoning = true;
400
+ if (Array.isArray(reasoning.effort_options)) {
401
+ info.effortOptions = reasoning.effort_options.filter((option) => typeof option === "string");
402
+ }
403
+ }
404
+ }
405
+ }
406
+ parseGatewayMetaFields(json, info);
407
+ return probeInfoSummary(info).length > 0 ? info : void 0;
408
+ }
409
+ function parseModelGroupInfo(json, out) {
410
+ if (!json || typeof json !== "object") return false;
411
+ const entries = Array.isArray(json) ? json : Array.isArray(json.data) ? json.data : [];
412
+ if (entries.length === 0) return false;
413
+ let found = false;
414
+ for (const entry of entries) {
415
+ if (!entry || typeof entry !== "object") continue;
416
+ const name = typeof entry.model_group === "string" ? entry.model_group.trim() : "";
417
+ if (!name) continue;
418
+ const parsed = {};
419
+ const contextWindow = firstFiniteNumber(entry, "max_input_tokens", "context_window");
420
+ if (contextWindow !== void 0) parsed.contextWindow = contextWindow;
421
+ const maxTokens = firstFiniteNumber(entry, "max_output_tokens", "max_tokens");
422
+ if (maxTokens !== void 0) parsed.maxTokens = maxTokens;
423
+ if (typeof entry.supports_vision === "boolean") parsed.image = entry.supports_vision;
424
+ if (typeof entry.supports_reasoning === "boolean") parsed.reasoning = entry.supports_reasoning;
425
+ if (probeInfoSummary(parsed).length > 0) {
426
+ out.set(name, parsed);
427
+ found = true;
428
+ }
429
+ }
430
+ return found;
431
+ }
432
+ async function enrichLiteLLMModelGroupInfo(baseUrl, apiKey) {
433
+ const out = /* @__PURE__ */ new Map();
434
+ if (!apiKey) return out;
435
+ const headers = { accept: "application/json", authorization: `Bearer ${apiKey}` };
436
+ let roots;
437
+ try {
438
+ roots = [new URL(baseUrl).origin, baseUrl];
439
+ } catch {
440
+ roots = [baseUrl];
441
+ }
442
+ for (const root of roots) {
443
+ try {
444
+ const controller = new AbortController();
445
+ const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
446
+ const response = await fetch(`${root.replace(/\/+$/, "")}/model_group/info`, {
447
+ headers,
448
+ signal: controller.signal
449
+ });
450
+ clearTimeout(timer);
451
+ if (!response.ok) continue;
452
+ const json = await response.json().catch(() => null);
453
+ if (parseModelGroupInfo(json, out)) return out;
454
+ } catch {
455
+ }
456
+ }
457
+ return out;
458
+ }
459
+ function parsePublicModelList(json, out) {
460
+ if (!Array.isArray(json)) return false;
461
+ let found = false;
462
+ for (const entry of json) {
463
+ if (!entry || typeof entry !== "object") continue;
464
+ const name = typeof entry.litellm_model_name === "string" ? entry.litellm_model_name.trim() : typeof entry.model_name === "string" ? entry.model_name.trim() : typeof entry.id === "string" ? entry.id.trim() : "";
465
+ if (!name) continue;
466
+ if (entry.status === "draft" || entry.status === "archived" || entry.is_visible === false) continue;
467
+ const parsed = {};
468
+ const contextWindow = firstFiniteNumber(entry, "context_window", "contextWindow", "max_input_tokens");
469
+ if (contextWindow !== void 0) parsed.contextWindow = contextWindow;
470
+ const maxTokens = firstFiniteNumber(entry, "max_output_tokens", "maxTokens", "max_tokens");
471
+ if (maxTokens !== void 0) parsed.maxTokens = maxTokens;
472
+ if (typeof entry.supports_vision === "boolean") parsed.image = entry.supports_vision;
473
+ if (typeof entry.supports_reasoning === "boolean") parsed.reasoning = entry.supports_reasoning;
474
+ if (probeInfoSummary(parsed).length > 0) {
475
+ out.set(name, parsed);
476
+ found = true;
477
+ }
478
+ }
479
+ return found;
480
+ }
481
+ async function enrichPublicModelInfo(baseUrl) {
482
+ const out = /* @__PURE__ */ new Map();
483
+ const roots = /* @__PURE__ */ new Set();
484
+ try {
485
+ const url = new URL(baseUrl);
486
+ roots.add(url.origin);
487
+ roots.add(`https://${url.hostname.replace(/^api\./i, "")}`);
488
+ } catch {
489
+ roots.add(baseUrl);
490
+ }
491
+ for (const root of roots) {
492
+ try {
493
+ const controller = new AbortController();
494
+ const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
495
+ const response = await fetch(`${root.replace(/\/+$/, "")}/api/models/public`, {
496
+ headers: { accept: "application/json" },
497
+ signal: controller.signal
498
+ });
499
+ clearTimeout(timer);
500
+ if (!response.ok) continue;
501
+ const json = await response.json().catch(() => null);
502
+ if (parsePublicModelList(json, out)) return out;
503
+ } catch {
504
+ }
505
+ }
506
+ return out;
507
+ }
508
+ function parseLiteLLMModelInfo(json, out) {
509
+ if (!json || typeof json !== "object") return false;
510
+ const entries = Array.isArray(json.data) ? json.data : Array.isArray(json?.data?.data) ? json.data.data : [];
511
+ if (entries.length === 0) return false;
512
+ let found = false;
513
+ for (const entry of entries) {
514
+ if (!entry || typeof entry !== "object") continue;
515
+ const name = typeof entry.model_name === "string" ? entry.model_name.trim() : "";
516
+ const info = entry.model_info;
517
+ if (!name || !info || typeof info !== "object") continue;
518
+ const parsed = {};
519
+ const contextWindow = firstFiniteNumber(info, "context_window", "max_input_tokens");
520
+ if (contextWindow !== void 0) parsed.contextWindow = contextWindow;
521
+ const maxTokens = firstFiniteNumber(info, "max_output_tokens", "max_tokens");
522
+ if (maxTokens !== void 0) parsed.maxTokens = maxTokens;
523
+ if (typeof info.supports_vision === "boolean") parsed.image = info.supports_vision;
524
+ if (typeof info.supports_reasoning === "boolean") parsed.reasoning = info.supports_reasoning;
525
+ if (probeInfoSummary(parsed).length > 0) {
526
+ out.set(name, parsed);
527
+ found = true;
528
+ }
529
+ }
530
+ return found;
531
+ }
532
+ async function enrichLiteLLMModelInfo(baseUrl, apiKey) {
533
+ const headers = { accept: "application/json", "accept-encoding": "identity" };
534
+ if (apiKey) headers.authorization = `Bearer ${apiKey}`;
535
+ const out = /* @__PURE__ */ new Map();
536
+ let roots;
537
+ try {
538
+ const origin = new URL(baseUrl).origin;
539
+ const trimmedBase = baseUrl.replace(/\/+$/, "");
540
+ roots = origin === trimmedBase ? [trimmedBase] : [origin, trimmedBase];
541
+ } catch {
542
+ roots = [baseUrl.replace(/\/+$/, "")];
543
+ }
544
+ for (const root of roots) {
545
+ const controller = new AbortController();
546
+ const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
547
+ let response;
548
+ try {
549
+ response = await fetch(`${root}/model/info`, { headers, signal: controller.signal });
550
+ } catch {
551
+ } finally {
552
+ clearTimeout(timer);
553
+ }
554
+ if (response?.ok) {
555
+ const json = await response.json().catch(() => null);
556
+ if (parseLiteLLMModelInfo(json, out)) return out;
557
+ }
558
+ }
559
+ return out;
560
+ }
561
+ async function enrichOpenAIModelDetails(baseUrl, apiKey, ids) {
562
+ const headers = { accept: "application/json", "accept-encoding": "identity" };
563
+ if (apiKey) {
564
+ headers.authorization = `Bearer ${apiKey}`;
565
+ headers["x-goog-api-key"] = apiKey;
566
+ }
567
+ const base = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
568
+ const out = /* @__PURE__ */ new Map();
569
+ let cursor = 0;
570
+ async function worker() {
571
+ while (cursor < ids.length) {
572
+ const id = ids[cursor++];
573
+ try {
574
+ const controller = new AbortController();
575
+ const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
576
+ const response = await fetch(new URL(`models/${encodeURIComponent(id)}`, base).toString(), {
577
+ headers,
578
+ signal: controller.signal
579
+ });
580
+ clearTimeout(timer);
581
+ if (!response.ok) continue;
582
+ const json = await response.json().catch(() => null);
583
+ const info = parseOpenAIModelDetail(json);
584
+ if (info) out.set(id, info);
585
+ } catch {
586
+ }
587
+ }
588
+ }
589
+ await Promise.all(Array.from({ length: Math.min(PROBE_CONCURRENCY, Math.max(1, ids.length)) }, worker));
590
+ return out;
591
+ }
592
+ function ollamaNativeRoot(baseUrl) {
593
+ try {
594
+ const url = new URL(baseUrl);
595
+ const pathname = url.pathname.replace(/\/+$/, "");
596
+ if (pathname.endsWith("/v1")) url.pathname = pathname.slice(0, -3) || "/";
597
+ return url.toString().replace(/\/+$/, "");
598
+ } catch {
599
+ return null;
600
+ }
601
+ }
602
+ async function enrichOllamaModelDetails(baseUrl, apiKey, ids) {
603
+ const root = ollamaNativeRoot(baseUrl);
604
+ if (!root) return /* @__PURE__ */ new Map();
605
+ const out = /* @__PURE__ */ new Map();
606
+ const headers = { accept: "application/json" };
607
+ if (apiKey) headers.authorization = `Bearer ${apiKey}`;
608
+ try {
609
+ const controller = new AbortController();
610
+ const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
611
+ const response = await fetch(`${root}/api/tags`, { headers, signal: controller.signal });
612
+ clearTimeout(timer);
613
+ if (response.ok) {
614
+ const json = await response.json().catch(() => null);
615
+ for (const model of Array.isArray(json?.models) ? json.models : []) {
616
+ const name = typeof model?.name === "string" ? model.name.trim() : "";
617
+ if (!name) continue;
618
+ const info = {};
619
+ if (Array.isArray(model.capabilities)) info.image = model.capabilities.includes("vision");
620
+ if (Object.keys(info).length > 0) out.set(name, info);
621
+ }
622
+ }
623
+ } catch {
624
+ }
625
+ let cursor = 0;
626
+ async function worker() {
627
+ while (cursor < ids.length) {
628
+ const id = ids[cursor++];
629
+ try {
630
+ const controller = new AbortController();
631
+ const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
632
+ const response = await fetch(`${root}/api/show`, {
633
+ method: "POST",
634
+ headers: { "content-type": "application/json", ...headers },
635
+ body: JSON.stringify({ name: id }),
636
+ signal: controller.signal
637
+ });
638
+ clearTimeout(timer);
639
+ if (!response.ok) continue;
640
+ const json = await response.json().catch(() => null);
641
+ const info = { ...out.get(id) ?? {} };
642
+ const modelInfo = json?.model_info;
643
+ if (modelInfo && typeof modelInfo === "object") {
644
+ for (const [key, value] of Object.entries(modelInfo)) {
645
+ if (key.endsWith(".context_length") && typeof value === "number" && value > 0) {
646
+ info.contextWindow = value;
647
+ }
648
+ }
649
+ }
650
+ if (Array.isArray(json?.capabilities)) info.image = json.capabilities.includes("vision");
651
+ out.set(id, info);
652
+ } catch {
653
+ }
654
+ }
655
+ }
656
+ await Promise.all(Array.from({ length: Math.min(PROBE_CONCURRENCY, Math.max(1, ids.length)) }, worker));
657
+ return out;
658
+ }
659
+
660
+ // release/node_modules/model-probe/src/developer-role.ts
661
+ async function probeDeveloperRole(baseUrl, apiKey, modelId) {
662
+ const headers = {
663
+ accept: "application/json",
664
+ "content-type": "application/json"
665
+ };
666
+ if (apiKey) headers.authorization = `Bearer ${apiKey}`;
667
+ const controller = new AbortController();
668
+ const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
669
+ let response;
670
+ try {
671
+ response = await fetch(`${baseUrl.replace(/\/+$/, "")}/chat/completions`, {
672
+ method: "POST",
673
+ headers,
674
+ body: JSON.stringify({
675
+ model: modelId,
676
+ messages: [
677
+ { role: "developer", content: "You are a helpful assistant." },
678
+ { role: "user", content: "Say ok." }
679
+ ],
680
+ max_tokens: 1,
681
+ stream: false
682
+ }),
683
+ signal: controller.signal
684
+ });
685
+ } catch {
686
+ return void 0;
687
+ } finally {
688
+ clearTimeout(timer);
689
+ }
690
+ if (response.ok) return true;
691
+ if (response.status >= 400 && response.status < 500) {
692
+ const body = await response.text().catch(() => "");
693
+ if (/developer/i.test(body) || /role[^a-z]{0,20}(not|invalid|unsupported|unknown)/i.test(body)) return false;
694
+ }
695
+ return void 0;
696
+ }
697
+
698
+ // release/node_modules/model-probe/src/modelsdev.ts
699
+ import { existsSync as existsSync2, readdirSync, unlinkSync, writeFileSync } from "node:fs";
700
+ import { tmpdir } from "node:os";
701
+ import { join as join2 } from "node:path";
702
+ import { pathToFileURL } from "node:url";
703
+ import { Models } from "./opencode-models.js";
704
+ var DEFAULT_BASE_URLS = {
705
+ openai: "https://api.openai.com/v1",
706
+ groq: "https://api.groq.com/openai/v1",
707
+ mistral: "https://api.mistral.ai/v1",
708
+ xai: "https://api.x.ai/v1",
709
+ cerebras: "https://api.cerebras.ai/v1",
710
+ togetherai: "https://api.together.xyz/v1",
711
+ deepinfra: "https://api.deepinfra.com/v1/openai",
712
+ perplexity: "https://api.perplexity.ai",
713
+ venice: "https://api.venice.ai/api/v1",
714
+ aihubmix: "https://aihubmix.com/v1"
715
+ };
716
+ var catalogCache = null;
717
+ var catalogPromise = null;
718
+ var SNAPSHOT_CDN_URL = "https://cdn.jsdelivr.net/npm/@opencode-ai/models@latest/dist/snapshot.js";
719
+ async function loadLatestSnapshot() {
720
+ const day = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
721
+ const file = join2(tmpdir(), `model-probe-modelsdev-${day}.mjs`);
722
+ if (!existsSync2(file)) {
723
+ const controller = new AbortController();
724
+ const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS * 2);
725
+ try {
726
+ const response = await fetch(SNAPSHOT_CDN_URL, { headers: { "user-agent": "model-probe" }, signal: controller.signal });
727
+ if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
728
+ const text = await response.text();
729
+ if (!text.includes("providers")) throw new Error("unexpected snapshot content");
730
+ writeFileSync(file, text);
731
+ for (const old of readdirSync(tmpdir())) {
732
+ if (old.startsWith("model-probe-modelsdev-") && old !== `model-probe-modelsdev-${day}.mjs`) {
733
+ try {
734
+ unlinkSync(join2(tmpdir(), old));
735
+ } catch {
736
+ }
737
+ }
738
+ }
739
+ } finally {
740
+ clearTimeout(timer);
741
+ }
742
+ }
743
+ const mod = await import(pathToFileURL(file).href);
744
+ const providers = mod.providers ?? mod.default?.providers;
745
+ if (!providers || Object.keys(providers).length === 0) throw new Error("snapshot had no providers");
746
+ return providers;
747
+ }
748
+ async function loadCatalog() {
749
+ if (catalogCache) return catalogCache;
750
+ catalogPromise ??= (async () => {
751
+ try {
752
+ const client = Models.make();
753
+ const map = await client.providers({ signal: AbortSignal.timeout(PROBE_TIMEOUT_MS * 2) });
754
+ if (!map || Object.keys(map).length === 0) throw new Error("models.dev returned no providers");
755
+ catalogCache = map;
756
+ return map;
757
+ } catch {
758
+ }
759
+ try {
760
+ catalogCache = await loadLatestSnapshot();
761
+ return catalogCache;
762
+ } catch {
763
+ }
764
+ const snapshot = await import("./opencode-models-snapshot.js");
765
+ catalogCache = snapshot.providers;
766
+ return catalogCache;
767
+ })();
768
+ return catalogPromise;
769
+ }
770
+ function toProviderEntry(provider) {
771
+ const baseUrl = provider.api?.trim() || DEFAULT_BASE_URLS[provider.id];
772
+ if (!baseUrl) return null;
773
+ return {
774
+ id: provider.id,
775
+ name: provider.name?.trim() || provider.id,
776
+ baseUrl: baseUrl.replace(/\/+$/, ""),
777
+ env: Array.isArray(provider.env) ? provider.env.filter((v) => typeof v === "string") : [],
778
+ doc: provider.doc
779
+ };
780
+ }
781
+ function parseModelEntry(model) {
782
+ const info = {};
783
+ if (Number.isFinite(model.limit?.context) && model.limit.context > 0) info.contextWindow = model.limit.context;
784
+ if (Number.isFinite(model.limit?.output) && model.limit.output > 0) info.maxTokens = model.limit.output;
785
+ if (info.contextWindow !== void 0 && info.maxTokens !== void 0) {
786
+ const limited = normalizeModelLimits(info.contextWindow, info.maxTokens);
787
+ info.contextWindow = limited.contextWindow;
788
+ info.maxTokens = limited.maxTokens;
789
+ }
790
+ if (Array.isArray(model.modalities?.input)) {
791
+ info.image = model.modalities.input.includes("image");
792
+ info.video = model.modalities.input.includes("video");
793
+ }
794
+ if (typeof model.reasoning === "boolean") info.reasoning = model.reasoning;
795
+ const effort = model.reasoning_options?.find((o) => o.type === "effort");
796
+ if (effort && effort.type === "effort") {
797
+ info.effortOptions = effort.values.filter((v) => typeof v === "string");
798
+ }
799
+ return Object.keys(info).length > 0 ? info : void 0;
800
+ }
801
+ async function fetchModelsDevProviders() {
802
+ const catalog = await loadCatalog();
803
+ const out = /* @__PURE__ */ new Map();
804
+ for (const provider of Object.values(catalog)) {
805
+ if (!provider || typeof provider !== "object") continue;
806
+ const entry = toProviderEntry(provider);
807
+ if (entry) out.set(entry.id, entry);
808
+ }
809
+ if (out.size === 0) throw new Error("models.dev catalog contained no usable providers");
810
+ return out;
811
+ }
812
+ async function fetchModelsDevModels(providerId) {
813
+ const catalog = await loadCatalog();
814
+ const out = /* @__PURE__ */ new Map();
815
+ const models = catalog[providerId]?.models;
816
+ if (models && typeof models === "object") {
817
+ for (const [id, model] of Object.entries(models)) {
818
+ const info = parseModelEntry(model);
819
+ if (info) out.set(id, info);
820
+ }
821
+ }
822
+ return out;
823
+ }
824
+ function sameBaseUrl(a, b) {
825
+ try {
826
+ const ua = new URL(a);
827
+ const ub = new URL(b);
828
+ if (ua.host.toLowerCase() !== ub.host.toLowerCase()) return false;
829
+ const strip = (p) => p.replace(/\/+$/, "").replace(/\/v1$/i, "");
830
+ return strip(ua.pathname) === strip(ub.pathname);
831
+ } catch {
832
+ return false;
833
+ }
834
+ }
835
+ async function fetchModelsDevInfoForBaseUrl(baseUrl) {
836
+ try {
837
+ const providers = await fetchModelsDevProviders();
838
+ for (const provider of providers.values()) {
839
+ if (sameBaseUrl(provider.baseUrl, baseUrl)) {
840
+ return await fetchModelsDevModels(provider.id);
841
+ }
842
+ }
843
+ } catch {
844
+ }
845
+ return /* @__PURE__ */ new Map();
846
+ }
847
+
848
+ // release/node_modules/model-probe/src/detect.ts
849
+ async function fetchGatewayWideInfo(baseUrl, options = {}) {
850
+ const out = /* @__PURE__ */ new Map();
851
+ if (options.ollama) return out;
852
+ const profile = { ...FULL_PROFILE, ...options.profile };
853
+ if (profile.modelInfo) {
854
+ for (const [id, info] of await enrichLiteLLMModelInfo(baseUrl, options.apiKey)) {
855
+ out.set(id, info);
856
+ }
857
+ }
858
+ if (profile.publicCatalog) {
859
+ for (const [id, info] of await enrichPublicModelInfo(baseUrl)) {
860
+ out.set(id, { ...out.get(id) ?? {}, ...info });
861
+ }
862
+ }
863
+ if (profile.modelGroupInfo) {
864
+ for (const [id, info] of await enrichLiteLLMModelGroupInfo(baseUrl, options.apiKey)) {
865
+ const existing = out.get(id);
866
+ if (!existing) {
867
+ out.set(id, info);
868
+ continue;
869
+ }
870
+ const filled = { ...existing };
871
+ if (filled.contextWindow === void 0 && info.contextWindow !== void 0) filled.contextWindow = info.contextWindow;
872
+ if (filled.maxTokens === void 0 && info.maxTokens !== void 0) filled.maxTokens = info.maxTokens;
873
+ if (filled.image === void 0 && info.image !== void 0) filled.image = info.image;
874
+ if (filled.video === void 0 && info.video !== void 0) filled.video = info.video;
875
+ if (filled.reasoning === void 0 && info.reasoning !== void 0) filled.reasoning = info.reasoning;
876
+ out.set(id, filled);
877
+ }
878
+ }
879
+ return out;
880
+ }
881
+ async function fetchPerModelInfo(baseUrl, ids, options = {}) {
882
+ if (options.ollama) return enrichOllamaModelDetails(baseUrl, options.apiKey, ids);
883
+ return enrichOpenAIModelDetails(baseUrl, options.apiKey, ids);
884
+ }
885
+ function applyModelsDevFallback(info, modelsDev) {
886
+ if (!modelsDev) return info;
887
+ const out = { ...info ?? {} };
888
+ const tagged = [...info?.modelsDevFields ?? []];
889
+ for (const field of ["contextWindow", "maxTokens", "image", "video", "reasoning"]) {
890
+ if (out[field] === void 0 && modelsDev[field] !== void 0) {
891
+ out[field] = modelsDev[field];
892
+ tagged.push(field);
893
+ }
894
+ }
895
+ if (out.effortOptions === void 0 && modelsDev.effortOptions !== void 0) out.effortOptions = modelsDev.effortOptions;
896
+ if (tagged.length > 0) out.modelsDevFields = tagged;
897
+ return out;
898
+ }
899
+ function applyApiFallback(info, api) {
900
+ const fallback = api ? API_FALLBACK_LIMITS[api] : void 0;
901
+ if (!fallback) return info;
902
+ const out = { ...info };
903
+ const defaulted = [...info.defaultedFields ?? []];
904
+ if (out.contextWindow === void 0) {
905
+ out.contextWindow = fallback.contextWindow;
906
+ defaulted.push("contextWindow");
907
+ }
908
+ if (out.maxTokens === void 0) {
909
+ out.maxTokens = fallback.maxTokens;
910
+ defaulted.push("maxTokens");
911
+ }
912
+ out.defaultedFields = defaulted;
913
+ return out;
914
+ }
915
+ function resolveModelInfo(modelId, info, modelsDev, api) {
916
+ return applyModelDefaults(applyApiFallback(applyKnownModelFallback(modelId, applyModelsDevFallback(info, modelsDev?.get(modelId))) ?? {}, api));
917
+ }
918
+ function finalizeModelInfo(ids, maps, options = {}) {
919
+ const merged = /* @__PURE__ */ new Map();
920
+ for (const map of maps) {
921
+ for (const [id, info] of map) {
922
+ merged.set(id, { ...merged.get(id) ?? {}, ...info });
923
+ }
924
+ }
925
+ for (const id of ids) {
926
+ merged.set(id, resolveModelInfo(id, merged.get(id), options.modelsDev, options.api));
927
+ }
928
+ return merged;
929
+ }
930
+ async function detectModels(baseUrl, options = {}) {
931
+ const profile = { ...FULL_PROFILE, ...options.profile };
932
+ const probed = await probeModels(baseUrl, options.apiKey);
933
+ const gatewayWide = await fetchGatewayWideInfo(probed.baseUrl, { apiKey: options.apiKey, profile, ollama: options.ollama });
934
+ let details = /* @__PURE__ */ new Map();
935
+ if (options.ollama) {
936
+ details = await fetchPerModelInfo(probed.baseUrl, probed.ids, { apiKey: options.apiKey, ollama: true });
937
+ } else if (profile.perModelDetails && gatewayWide.size === 0) {
938
+ details = await fetchPerModelInfo(probed.baseUrl, probed.ids, { apiKey: options.apiKey });
939
+ }
940
+ let modelsDev = /* @__PURE__ */ new Map();
941
+ if (profile.modelsDev) {
942
+ modelsDev = await fetchModelsDevInfoForBaseUrl(probed.baseUrl);
943
+ }
944
+ const models = options.knownModelFallback === false ? finalizeModelInfo([], [probed.infoById, gatewayWide, details]) : finalizeModelInfo(probed.ids, [probed.infoById, gatewayWide, details], { modelsDev, api: options.api });
945
+ const result = { ...probed, models };
946
+ if (options.developerRole) {
947
+ const probedRole = probed.ids.length > 0 ? await probeDeveloperRole(probed.baseUrl, options.apiKey, probed.ids[0]) : void 0;
948
+ result.supportsDeveloperRole = probedRole ?? false;
949
+ result.developerRoleSource = probedRole === void 0 ? "default" : "detected";
950
+ }
951
+ return result;
952
+ }
953
+ export {
954
+ API_FALLBACK_LIMITS,
955
+ FULL_PROFILE,
956
+ MAX_OUTPUT_TOKEN_CAP,
957
+ MODEL_INFO_DEFAULTS,
958
+ PROBE_CONCURRENCY,
959
+ PROBE_TIMEOUT_MS,
960
+ applyKnownModelFallback,
961
+ applyModelDefaults,
962
+ describeProbeInfo,
963
+ detectModels,
964
+ enrichLiteLLMModelGroupInfo,
965
+ enrichLiteLLMModelInfo,
966
+ enrichOllamaModelDetails,
967
+ enrichOpenAIModelDetails,
968
+ enrichPublicModelInfo,
969
+ fetchGatewayWideInfo,
970
+ fetchModelsDevInfoForBaseUrl,
971
+ fetchModelsDevModels,
972
+ fetchModelsDevProviders,
973
+ fetchPerModelInfo,
974
+ finalizeModelInfo,
975
+ normalizeModelIdCandidates,
976
+ normalizeModelLimits,
977
+ probeDeveloperRole,
978
+ probeInfoSummary,
979
+ probeModels,
980
+ registerKnownModelRules,
981
+ reloadKnownModelRules,
982
+ resolveModelInfo
983
+ };