@agentmark-ai/model-registry 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,367 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
31
+
32
+ // src/index.ts
33
+ var index_exports = {};
34
+ __export(index_exports, {
35
+ ModelRegistryImpl: () => ModelRegistryImpl,
36
+ getModelRegistry: () => getModelRegistry,
37
+ getModelRegistryAsync: () => getModelRegistryAsync2,
38
+ modelsFileSchema: () => modelsFileSchema,
39
+ overridesFileSchema: () => overridesFileSchema,
40
+ resetRegistryCache: () => resetRegistryCache
41
+ });
42
+ module.exports = __toCommonJS(index_exports);
43
+ var fs = __toESM(require("fs"));
44
+ var path = __toESM(require("path"));
45
+
46
+ // src/validation.ts
47
+ var import_zod = require("zod");
48
+ var modelModeSchema = import_zod.z.enum([
49
+ "chat",
50
+ "embedding",
51
+ "image_generation",
52
+ "audio_speech",
53
+ "audio_transcription",
54
+ "moderation",
55
+ "rerank"
56
+ ]);
57
+ var modelPricingSchema = import_zod.z.object({
58
+ inputCostPerToken: import_zod.z.number(),
59
+ outputCostPerToken: import_zod.z.number(),
60
+ cacheCreationCostPerToken: import_zod.z.number().optional(),
61
+ cacheReadCostPerToken: import_zod.z.number().optional()
62
+ }).strict();
63
+ var modelContextSchema = import_zod.z.object({
64
+ maxInputTokens: import_zod.z.number().positive().optional(),
65
+ maxOutputTokens: import_zod.z.number().positive().optional()
66
+ }).strict().refine(
67
+ (ctx) => {
68
+ if (ctx.maxInputTokens !== void 0 && ctx.maxOutputTokens !== void 0) {
69
+ return ctx.maxOutputTokens <= ctx.maxInputTokens;
70
+ }
71
+ return true;
72
+ },
73
+ {
74
+ message: "maxOutputTokens must be <= maxInputTokens"
75
+ }
76
+ );
77
+ var modelCapabilitiesSchema = import_zod.z.object({
78
+ vision: import_zod.z.boolean().optional(),
79
+ functionCalling: import_zod.z.boolean().optional(),
80
+ parallelFunctionCalling: import_zod.z.boolean().optional(),
81
+ structuredOutput: import_zod.z.boolean().optional(),
82
+ promptCaching: import_zod.z.boolean().optional(),
83
+ reasoning: import_zod.z.boolean().optional(),
84
+ audioInput: import_zod.z.boolean().optional(),
85
+ audioOutput: import_zod.z.boolean().optional(),
86
+ pdfInput: import_zod.z.boolean().optional(),
87
+ webSearch: import_zod.z.boolean().optional()
88
+ }).strict();
89
+ var isoDatePattern = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?Z?)?$/;
90
+ var modelEntryWithoutIdSchema = import_zod.z.object({
91
+ provider: import_zod.z.string().min(1),
92
+ displayName: import_zod.z.string().min(1),
93
+ mode: modelModeSchema,
94
+ pricing: modelPricingSchema.optional(),
95
+ context: modelContextSchema.optional(),
96
+ capabilities: modelCapabilitiesSchema.optional(),
97
+ deprecationDate: import_zod.z.string().regex(isoDatePattern, "Must be a valid ISO 8601 date").nullable().optional(),
98
+ source: import_zod.z.string().optional(),
99
+ supportedParameters: import_zod.z.array(import_zod.z.string()).optional()
100
+ });
101
+ var sourceInfoSchema = import_zod.z.object({
102
+ fetchedAt: import_zod.z.string(),
103
+ modelCount: import_zod.z.number()
104
+ });
105
+ var modelsFileSchema = import_zod.z.object({
106
+ $schema: import_zod.z.string().optional(),
107
+ version: import_zod.z.string().min(1),
108
+ generatedAt: import_zod.z.string().min(1),
109
+ sources: import_zod.z.record(import_zod.z.string(), sourceInfoSchema),
110
+ models: import_zod.z.record(import_zod.z.string(), modelEntryWithoutIdSchema)
111
+ });
112
+ var partialModelEntrySchema = import_zod.z.object({
113
+ provider: import_zod.z.string().min(1).optional(),
114
+ displayName: import_zod.z.string().min(1).optional(),
115
+ mode: modelModeSchema.optional(),
116
+ pricing: modelPricingSchema.optional(),
117
+ context: modelContextSchema.optional(),
118
+ capabilities: modelCapabilitiesSchema.optional(),
119
+ deprecationDate: import_zod.z.string().regex(isoDatePattern, "Must be a valid ISO 8601 date").nullable().optional(),
120
+ source: import_zod.z.string().optional(),
121
+ supportedParameters: import_zod.z.array(import_zod.z.string()).optional()
122
+ });
123
+ var overridesFileSchema = import_zod.z.object({
124
+ $schema: import_zod.z.string().optional(),
125
+ models: import_zod.z.record(import_zod.z.string(), partialModelEntrySchema)
126
+ });
127
+
128
+ // src/compat.ts
129
+ function getPricingDictionary(models) {
130
+ const result = {};
131
+ for (const [id, entry] of models) {
132
+ if (entry.pricing) {
133
+ result[id] = {
134
+ promptPrice: entry.pricing.inputCostPerToken * 1e3,
135
+ completionPrice: entry.pricing.outputCostPerToken * 1e3
136
+ };
137
+ }
138
+ }
139
+ return result;
140
+ }
141
+ function getProviderModels(models, providerLabels) {
142
+ var _a;
143
+ const result = {};
144
+ for (const [id, entry] of models) {
145
+ if (!result[entry.provider]) {
146
+ result[entry.provider] = {
147
+ label: (_a = providerLabels[entry.provider]) != null ? _a : entry.provider,
148
+ languageModels: [],
149
+ imageModels: [],
150
+ speechModels: []
151
+ };
152
+ }
153
+ const group = result[entry.provider];
154
+ switch (entry.mode) {
155
+ case "chat":
156
+ case "embedding":
157
+ case "moderation":
158
+ case "rerank":
159
+ group.languageModels.push(id);
160
+ break;
161
+ case "image_generation":
162
+ group.imageModels.push(id);
163
+ break;
164
+ case "audio_speech":
165
+ group.speechModels.push(id);
166
+ break;
167
+ case "audio_transcription":
168
+ group.languageModels.push(id);
169
+ break;
170
+ }
171
+ }
172
+ return result;
173
+ }
174
+
175
+ // src/registry.ts
176
+ var ModelRegistryImpl = class {
177
+ constructor(modelsFile, overridesFile, providerLabels = {}) {
178
+ __publicField(this, "models");
179
+ __publicField(this, "providerLabels");
180
+ this.providerLabels = providerLabels;
181
+ this.models = /* @__PURE__ */ new Map();
182
+ for (const [id, entry] of Object.entries(modelsFile.models)) {
183
+ this.models.set(id, { id, ...entry });
184
+ }
185
+ if (overridesFile) {
186
+ for (const [id, overrideFields] of Object.entries(
187
+ overridesFile.models
188
+ )) {
189
+ const existing = this.models.get(id);
190
+ if (existing) {
191
+ this.models.set(id, { ...existing, ...overrideFields, id });
192
+ } else {
193
+ if (overrideFields.provider && overrideFields.displayName && overrideFields.mode) {
194
+ this.models.set(id, {
195
+ id,
196
+ provider: overrideFields.provider,
197
+ displayName: overrideFields.displayName,
198
+ mode: overrideFields.mode,
199
+ ...overrideFields
200
+ });
201
+ }
202
+ }
203
+ }
204
+ }
205
+ }
206
+ getProviders() {
207
+ var _a;
208
+ const providerCounts = /* @__PURE__ */ new Map();
209
+ for (const entry of this.models.values()) {
210
+ providerCounts.set(
211
+ entry.provider,
212
+ ((_a = providerCounts.get(entry.provider)) != null ? _a : 0) + 1
213
+ );
214
+ }
215
+ return Array.from(providerCounts.entries()).map(([id, count]) => {
216
+ var _a2;
217
+ return {
218
+ id,
219
+ label: (_a2 = this.providerLabels[id]) != null ? _a2 : id,
220
+ modelCount: count
221
+ };
222
+ });
223
+ }
224
+ getModelsByProvider(provider) {
225
+ const result = [];
226
+ for (const entry of this.models.values()) {
227
+ if (entry.provider === provider) {
228
+ result.push(entry);
229
+ }
230
+ }
231
+ return result;
232
+ }
233
+ getAllModels() {
234
+ return Array.from(this.models.values());
235
+ }
236
+ getModel(modelId) {
237
+ return this.models.get(modelId);
238
+ }
239
+ getPricingForModel(modelId) {
240
+ var _a;
241
+ return (_a = this.models.get(modelId)) == null ? void 0 : _a.pricing;
242
+ }
243
+ getCapabilitiesForModel(modelId) {
244
+ var _a;
245
+ return (_a = this.models.get(modelId)) == null ? void 0 : _a.capabilities;
246
+ }
247
+ findModelsByCapability(capability) {
248
+ var _a;
249
+ const result = [];
250
+ for (const entry of this.models.values()) {
251
+ if (((_a = entry.capabilities) == null ? void 0 : _a[capability]) === true) {
252
+ result.push(entry);
253
+ }
254
+ }
255
+ return result;
256
+ }
257
+ findDeprecatedModels() {
258
+ const result = [];
259
+ for (const entry of this.models.values()) {
260
+ if (entry.deprecationDate) {
261
+ result.push(entry);
262
+ }
263
+ }
264
+ return result;
265
+ }
266
+ getPricingDictionary() {
267
+ return getPricingDictionary(this.models);
268
+ }
269
+ getProviderModels() {
270
+ return getProviderModels(this.models, this.providerLabels);
271
+ }
272
+ };
273
+
274
+ // src/remote.ts
275
+ var CDN_BASE = "https://cdn.jsdelivr.net/gh/agentmark-ai/agentmark@main/packages/model-registry";
276
+ var MODELS_URL = `${CDN_BASE}/models.json`;
277
+ var OVERRIDES_URL = `${CDN_BASE}/overrides.json`;
278
+ var PROVIDER_LABELS_URL = `${CDN_BASE}/provider-labels.json`;
279
+ var FETCH_TIMEOUT_MS = 5e3;
280
+ var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
281
+ var cachedRemoteRegistry = null;
282
+ var cachedAt = 0;
283
+ function isStale() {
284
+ return Date.now() - cachedAt > CACHE_TTL_MS;
285
+ }
286
+ async function fetchJson(url) {
287
+ const res = await fetch(url, {
288
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
289
+ });
290
+ if (!res.ok) {
291
+ throw new Error(`HTTP ${res.status} fetching ${url}`);
292
+ }
293
+ return res.json();
294
+ }
295
+ async function fetchRemoteRegistry() {
296
+ try {
297
+ const [modelsRaw, overridesRaw, labelsRaw] = await Promise.all([
298
+ fetchJson(MODELS_URL),
299
+ fetchJson(OVERRIDES_URL).catch(() => null),
300
+ fetchJson(PROVIDER_LABELS_URL).catch(() => ({}))
301
+ ]);
302
+ const modelsFile = modelsFileSchema.parse(modelsRaw);
303
+ const overridesFile = overridesRaw ? overridesFileSchema.parse(overridesRaw) : void 0;
304
+ return new ModelRegistryImpl(
305
+ modelsFile,
306
+ overridesFile,
307
+ labelsRaw
308
+ );
309
+ } catch {
310
+ return null;
311
+ }
312
+ }
313
+ async function getModelRegistryAsync(localFallback) {
314
+ if (cachedRemoteRegistry && !isStale()) {
315
+ return cachedRemoteRegistry;
316
+ }
317
+ const remote = await fetchRemoteRegistry();
318
+ if (remote) {
319
+ cachedRemoteRegistry = remote;
320
+ cachedAt = Date.now();
321
+ return remote;
322
+ }
323
+ return localFallback();
324
+ }
325
+ function resetRemoteCache() {
326
+ cachedRemoteRegistry = null;
327
+ cachedAt = 0;
328
+ }
329
+
330
+ // src/index.ts
331
+ var cachedRegistry = null;
332
+ function getModelRegistry() {
333
+ if (cachedRegistry) {
334
+ return cachedRegistry;
335
+ }
336
+ const packageRoot = path.resolve(__dirname, "..");
337
+ const modelsPath = path.resolve(packageRoot, "models.json");
338
+ const overridesPath = path.resolve(packageRoot, "overrides.json");
339
+ const modelsRaw = JSON.parse(fs.readFileSync(modelsPath, "utf-8"));
340
+ const modelsFile = modelsFileSchema.parse(modelsRaw);
341
+ let overridesFile = void 0;
342
+ if (fs.existsSync(overridesPath)) {
343
+ const overridesRaw = JSON.parse(fs.readFileSync(overridesPath, "utf-8"));
344
+ overridesFile = overridesFileSchema.parse(overridesRaw);
345
+ }
346
+ const labelsPath = path.resolve(packageRoot, "provider-labels.json");
347
+ const providerLabels = fs.existsSync(labelsPath) ? JSON.parse(fs.readFileSync(labelsPath, "utf-8")) : {};
348
+ cachedRegistry = new ModelRegistryImpl(modelsFile, overridesFile, providerLabels);
349
+ return cachedRegistry;
350
+ }
351
+ async function getModelRegistryAsync2() {
352
+ return getModelRegistryAsync(() => getModelRegistry());
353
+ }
354
+ function resetRegistryCache() {
355
+ cachedRegistry = null;
356
+ resetRemoteCache();
357
+ }
358
+ // Annotate the CommonJS export names for ESM import in node:
359
+ 0 && (module.exports = {
360
+ ModelRegistryImpl,
361
+ getModelRegistry,
362
+ getModelRegistryAsync,
363
+ modelsFileSchema,
364
+ overridesFileSchema,
365
+ resetRegistryCache
366
+ });
367
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/validation.ts","../src/compat.ts","../src/registry.ts","../src/remote.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as path from \"path\";\nimport { modelsFileSchema, overridesFileSchema } from \"./validation.js\";\nimport { ModelRegistryImpl } from \"./registry.js\";\nimport type { ModelRegistry } from \"./types.js\";\nimport {\n getModelRegistryAsync as getModelRegistryAsyncImpl,\n resetRemoteCache,\n} from \"./remote.js\";\n\nexport type {\n ModelMode,\n ModelPricing,\n ModelContext,\n ModelCapabilities,\n ModelEntry,\n ProviderInfo,\n ModelsFile,\n OverridesFile,\n ModelRegistry,\n SyncResult,\n SyncChangelog,\n} from \"./types.js\";\n\nexport { modelsFileSchema, overridesFileSchema } from \"./validation.js\";\nexport { ModelRegistryImpl } from \"./registry.js\";\n\nlet cachedRegistry: ModelRegistry | null = null;\n\n/**\n * Factory function that reads models.json + overrides.json from disk,\n * validates via Zod, constructs ModelRegistryImpl, and returns it.\n * Singleton pattern: caches the registry after first load.\n */\nexport function getModelRegistry(): ModelRegistry {\n if (cachedRegistry) {\n return cachedRegistry;\n }\n\n const packageRoot = path.resolve(__dirname, \"..\");\n const modelsPath = path.resolve(packageRoot, \"models.json\");\n const overridesPath = path.resolve(packageRoot, \"overrides.json\");\n\n const modelsRaw = JSON.parse(fs.readFileSync(modelsPath, \"utf-8\"));\n const modelsFile = modelsFileSchema.parse(modelsRaw);\n\n let overridesFile = undefined;\n if (fs.existsSync(overridesPath)) {\n const overridesRaw = JSON.parse(fs.readFileSync(overridesPath, \"utf-8\"));\n overridesFile = overridesFileSchema.parse(overridesRaw);\n }\n\n const labelsPath = path.resolve(packageRoot, \"provider-labels.json\");\n const providerLabels: Record<string, string> = fs.existsSync(labelsPath)\n ? JSON.parse(fs.readFileSync(labelsPath, \"utf-8\"))\n : {};\n\n cachedRegistry = new ModelRegistryImpl(modelsFile, overridesFile, providerLabels);\n return cachedRegistry;\n}\n\n/**\n * Async factory that fetches fresh model data from the CDN, falling back\n * to the bundled copy on network failure. Use this in runtimes that\n * support async initialization (CLI commands, server cold start).\n */\nexport async function getModelRegistryAsync(): Promise<ModelRegistry> {\n return getModelRegistryAsyncImpl(() => getModelRegistry());\n}\n\n/**\n * Reset all caches (useful for testing).\n */\nexport function resetRegistryCache(): void {\n cachedRegistry = null;\n resetRemoteCache();\n}\n","import { z } from \"zod\";\n\nconst modelModeSchema = z.enum([\n \"chat\",\n \"embedding\",\n \"image_generation\",\n \"audio_speech\",\n \"audio_transcription\",\n \"moderation\",\n \"rerank\",\n]);\n\nconst modelPricingSchema = z\n .object({\n inputCostPerToken: z.number(),\n outputCostPerToken: z.number(),\n cacheCreationCostPerToken: z.number().optional(),\n cacheReadCostPerToken: z.number().optional(),\n })\n .strict();\n\nconst modelContextSchema = z\n .object({\n maxInputTokens: z.number().positive().optional(),\n maxOutputTokens: z.number().positive().optional(),\n })\n .strict()\n .refine(\n (ctx) => {\n if (\n ctx.maxInputTokens !== undefined &&\n ctx.maxOutputTokens !== undefined\n ) {\n return ctx.maxOutputTokens <= ctx.maxInputTokens;\n }\n return true;\n },\n {\n message: \"maxOutputTokens must be <= maxInputTokens\",\n }\n );\n\nconst modelCapabilitiesSchema = z\n .object({\n vision: z.boolean().optional(),\n functionCalling: z.boolean().optional(),\n parallelFunctionCalling: z.boolean().optional(),\n structuredOutput: z.boolean().optional(),\n promptCaching: z.boolean().optional(),\n reasoning: z.boolean().optional(),\n audioInput: z.boolean().optional(),\n audioOutput: z.boolean().optional(),\n pdfInput: z.boolean().optional(),\n webSearch: z.boolean().optional(),\n })\n .strict();\n\nconst isoDatePattern = /^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?Z?)?$/;\n\nconst modelEntryWithoutIdSchema = z.object({\n provider: z.string().min(1),\n displayName: z.string().min(1),\n mode: modelModeSchema,\n pricing: modelPricingSchema.optional(),\n context: modelContextSchema.optional(),\n capabilities: modelCapabilitiesSchema.optional(),\n deprecationDate: z\n .string()\n .regex(isoDatePattern, \"Must be a valid ISO 8601 date\")\n .nullable()\n .optional(),\n source: z.string().optional(),\n supportedParameters: z.array(z.string()).optional(),\n});\n\nconst sourceInfoSchema = z.object({\n fetchedAt: z.string(),\n modelCount: z.number(),\n});\n\nexport const modelsFileSchema = z.object({\n $schema: z.string().optional(),\n version: z.string().min(1),\n generatedAt: z.string().min(1),\n sources: z.record(z.string(), sourceInfoSchema),\n models: z.record(z.string(), modelEntryWithoutIdSchema),\n});\n\nconst partialModelEntrySchema = z.object({\n provider: z.string().min(1).optional(),\n displayName: z.string().min(1).optional(),\n mode: modelModeSchema.optional(),\n pricing: modelPricingSchema.optional(),\n context: modelContextSchema.optional(),\n capabilities: modelCapabilitiesSchema.optional(),\n deprecationDate: z\n .string()\n .regex(isoDatePattern, \"Must be a valid ISO 8601 date\")\n .nullable()\n .optional(),\n source: z.string().optional(),\n supportedParameters: z.array(z.string()).optional(),\n});\n\nexport const overridesFileSchema = z.object({\n $schema: z.string().optional(),\n models: z.record(z.string(), partialModelEntrySchema),\n});\n","import type { ModelEntry } from \"./types.js\";\n\n/**\n * Returns pricing in the legacy format used by llm-costs and analytics.\n * Prices are per 1K tokens (inputCostPerToken * 1000).\n */\nexport function getPricingDictionary(\n models: Map<string, ModelEntry>\n): Record<string, { promptPrice: number; completionPrice: number }> {\n const result: Record<\n string,\n { promptPrice: number; completionPrice: number }\n > = {};\n\n for (const [id, entry] of models) {\n if (entry.pricing) {\n result[id] = {\n promptPrice: entry.pricing.inputCostPerToken * 1000,\n completionPrice: entry.pricing.outputCostPerToken * 1000,\n };\n }\n }\n\n return result;\n}\n\n/**\n * Returns provider+model groupings matching the CLI's Providers structure.\n * Used by pull-models command for backward compatibility.\n */\nexport function getProviderModels(\n models: Map<string, ModelEntry>,\n providerLabels: Record<string, string>\n): Record<\n string,\n {\n label: string;\n languageModels: string[];\n imageModels: string[];\n speechModels: string[];\n }\n> {\n const result: Record<\n string,\n {\n label: string;\n languageModels: string[];\n imageModels: string[];\n speechModels: string[];\n }\n > = {};\n\n for (const [id, entry] of models) {\n if (!result[entry.provider]) {\n result[entry.provider] = {\n label: providerLabels[entry.provider] ?? entry.provider,\n languageModels: [],\n imageModels: [],\n speechModels: [],\n };\n }\n\n const group = result[entry.provider]!;\n\n switch (entry.mode) {\n case \"chat\":\n case \"embedding\":\n case \"moderation\":\n case \"rerank\":\n group.languageModels.push(id);\n break;\n case \"image_generation\":\n group.imageModels.push(id);\n break;\n case \"audio_speech\":\n group.speechModels.push(id);\n break;\n case \"audio_transcription\":\n group.languageModels.push(id);\n break;\n }\n }\n\n return result;\n}\n","import type {\n ModelCapabilities,\n ModelEntry,\n ModelPricing,\n ModelRegistry,\n ModelsFile,\n OverridesFile,\n ProviderInfo,\n} from \"./types.js\";\nimport {\n getPricingDictionary,\n getProviderModels,\n} from \"./compat.js\";\n\nexport class ModelRegistryImpl implements ModelRegistry {\n private models: Map<string, ModelEntry>;\n private providerLabels: Record<string, string>;\n\n constructor(\n modelsFile: ModelsFile,\n overridesFile?: OverridesFile,\n providerLabels: Record<string, string> = {}\n ) {\n this.providerLabels = providerLabels;\n this.models = new Map();\n\n // Load base models\n for (const [id, entry] of Object.entries(modelsFile.models)) {\n this.models.set(id, { id, ...entry });\n }\n\n // Apply overrides (shallow merge per model)\n if (overridesFile) {\n for (const [id, overrideFields] of Object.entries(\n overridesFile.models\n )) {\n const existing = this.models.get(id);\n if (existing) {\n this.models.set(id, { ...existing, ...overrideFields, id });\n } else {\n // Override adds a new model — requires provider, displayName, mode at minimum\n if (\n overrideFields.provider &&\n overrideFields.displayName &&\n overrideFields.mode\n ) {\n this.models.set(id, {\n id,\n provider: overrideFields.provider,\n displayName: overrideFields.displayName,\n mode: overrideFields.mode,\n ...overrideFields,\n });\n }\n }\n }\n }\n }\n\n getProviders(): ProviderInfo[] {\n const providerCounts = new Map<string, number>();\n for (const entry of this.models.values()) {\n providerCounts.set(\n entry.provider,\n (providerCounts.get(entry.provider) ?? 0) + 1\n );\n }\n\n return Array.from(providerCounts.entries()).map(([id, count]) => ({\n id,\n label: this.providerLabels[id] ?? id,\n modelCount: count,\n }));\n }\n\n getModelsByProvider(provider: string): ModelEntry[] {\n const result: ModelEntry[] = [];\n for (const entry of this.models.values()) {\n if (entry.provider === provider) {\n result.push(entry);\n }\n }\n return result;\n }\n\n getAllModels(): ModelEntry[] {\n return Array.from(this.models.values());\n }\n\n getModel(modelId: string): ModelEntry | undefined {\n return this.models.get(modelId);\n }\n\n getPricingForModel(modelId: string): ModelPricing | undefined {\n return this.models.get(modelId)?.pricing;\n }\n\n getCapabilitiesForModel(modelId: string): ModelCapabilities | undefined {\n return this.models.get(modelId)?.capabilities;\n }\n\n findModelsByCapability(capability: keyof ModelCapabilities): ModelEntry[] {\n const result: ModelEntry[] = [];\n for (const entry of this.models.values()) {\n if (entry.capabilities?.[capability] === true) {\n result.push(entry);\n }\n }\n return result;\n }\n\n findDeprecatedModels(): ModelEntry[] {\n const result: ModelEntry[] = [];\n for (const entry of this.models.values()) {\n if (entry.deprecationDate) {\n result.push(entry);\n }\n }\n return result;\n }\n\n getPricingDictionary(): Record<\n string,\n { promptPrice: number; completionPrice: number }\n > {\n return getPricingDictionary(this.models);\n }\n\n getProviderModels(): Record<\n string,\n {\n label: string;\n languageModels: string[];\n imageModels: string[];\n speechModels: string[];\n }\n > {\n return getProviderModels(this.models, this.providerLabels);\n }\n}\n","/**\n * Remote model registry fetching.\n *\n * Fetches models.json from a CDN (jsdelivr) so consumers get fresh data\n * without waiting for an npm release. Falls back to the bundled copy on\n * network failure.\n */\n\nimport { modelsFileSchema, overridesFileSchema } from \"./validation.js\";\nimport { ModelRegistryImpl } from \"./registry.js\";\nimport type { ModelRegistry, ModelsFile, OverridesFile } from \"./types.js\";\n\n// jsdelivr mirrors GitHub with no rate limits and ~24h edge cache.\nconst CDN_BASE =\n \"https://cdn.jsdelivr.net/gh/agentmark-ai/agentmark@main/packages/model-registry\";\n\nconst MODELS_URL = `${CDN_BASE}/models.json`;\nconst OVERRIDES_URL = `${CDN_BASE}/overrides.json`;\nconst PROVIDER_LABELS_URL = `${CDN_BASE}/provider-labels.json`;\n\n/** How long to wait for the CDN before falling back to bundled data. */\nconst FETCH_TIMEOUT_MS = 5_000;\n\n/** Cache TTL — avoid re-fetching within the same long-running process. */\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\n\nlet cachedRemoteRegistry: ModelRegistry | null = null;\nlet cachedAt = 0;\n\nfunction isStale(): boolean {\n return Date.now() - cachedAt > CACHE_TTL_MS;\n}\n\nasync function fetchJson<T>(url: string): Promise<T> {\n const res = await fetch(url, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} fetching ${url}`);\n }\n return res.json() as Promise<T>;\n}\n\n/**\n * Fetch the model registry from the CDN.\n * Returns null on any failure (network, parse, timeout).\n */\nasync function fetchRemoteRegistry(): Promise<ModelRegistry | null> {\n try {\n const [modelsRaw, overridesRaw, labelsRaw] = await Promise.all([\n fetchJson<unknown>(MODELS_URL),\n fetchJson<unknown>(OVERRIDES_URL).catch(() => null),\n fetchJson<Record<string, string>>(PROVIDER_LABELS_URL).catch(() => ({})),\n ]);\n\n const modelsFile: ModelsFile = modelsFileSchema.parse(modelsRaw);\n const overridesFile: OverridesFile | undefined = overridesRaw\n ? overridesFileSchema.parse(overridesRaw)\n : undefined;\n\n return new ModelRegistryImpl(\n modelsFile,\n overridesFile,\n labelsRaw as Record<string, string>\n );\n } catch {\n return null;\n }\n}\n\n/**\n * Get the model registry, fetching fresh data from the CDN.\n * Falls back to the provided local registry on network failure.\n *\n * @param localFallback - A sync function that returns the bundled registry.\n * Only called when the CDN is unreachable.\n */\nexport async function getModelRegistryAsync(\n localFallback: () => ModelRegistry\n): Promise<ModelRegistry> {\n if (cachedRemoteRegistry && !isStale()) {\n return cachedRemoteRegistry;\n }\n\n const remote = await fetchRemoteRegistry();\n if (remote) {\n cachedRemoteRegistry = remote;\n cachedAt = Date.now();\n return remote;\n }\n\n return localFallback();\n}\n\n/**\n * Reset the remote cache (useful for testing).\n */\nexport function resetRemoteCache(): void {\n cachedRemoteRegistry = null;\n cachedAt = 0;\n}\n"],"mappings":"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","names":["getModelRegistryAsync","_a","getModelRegistryAsync"]}