@agentproto/catalog-sync 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,609 @@
1
+ import { mkdirSync, writeFileSync, existsSync, readFileSync } from 'fs';
2
+ import { dirname, join, resolve } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { z } from 'zod';
5
+ import { ElevenLabsVoicesSnapshotSchema, mapElevenLabsVoices, MinimaxVoicesSnapshotSchema, mapMinimaxVoices } from '@agentproto/model-catalog/providers';
6
+
7
+ /**
8
+ * @agentproto/catalog-sync v0.1.0
9
+ * Build-time generator framework for @agentproto/model-catalog.
10
+ * Generates *.generated.ts from pinned provider sources.
11
+ */
12
+
13
+ // src/types.ts
14
+ function defineGenerator(g) {
15
+ return g;
16
+ }
17
+ var __dirname$1 = dirname(fileURLToPath(import.meta.url));
18
+ function catalogSyncDir() {
19
+ return resolve(__dirname$1, "..");
20
+ }
21
+ function snapshotPath(id) {
22
+ return join(catalogSyncDir(), "snapshots", `${id}.json`);
23
+ }
24
+ function repoRoot() {
25
+ let dir = catalogSyncDir();
26
+ for (let i = 0; i < 12; i++) {
27
+ if (existsSync(join(dir, "pnpm-workspace.yaml"))) return dir;
28
+ const parent = dirname(dir);
29
+ if (parent === dir) break;
30
+ dir = parent;
31
+ }
32
+ return dirname(dirname(catalogSyncDir()));
33
+ }
34
+ function readIfExists(absPath) {
35
+ if (!existsSync(absPath)) return void 0;
36
+ return readFileSync(absPath, "utf8");
37
+ }
38
+ function resolveHeaders(headers) {
39
+ const out = {};
40
+ const missing = [];
41
+ if (!headers) return { headers: out, missing };
42
+ for (const [key, value] of Object.entries(headers)) {
43
+ out[key] = value.replace(/env:([A-Z0-9_]+)/g, (_match, name) => {
44
+ const v = process.env[name];
45
+ if (v === void 0 || v === "") {
46
+ missing.push(name);
47
+ return "";
48
+ }
49
+ return v;
50
+ });
51
+ }
52
+ return { headers: out, missing };
53
+ }
54
+ async function runGenerators(gens, opts) {
55
+ const files = {};
56
+ for (const gen of gens) {
57
+ const ctx = {
58
+ refresh: opts.refresh,
59
+ async fetchSource(src) {
60
+ const path = snapshotPath(src.id);
61
+ const existing = readIfExists(path);
62
+ if (!opts.refresh) {
63
+ if (existing !== void 0) return JSON.parse(existing);
64
+ throw new Error(
65
+ `catalog-sync: no committed snapshot for source "${src.id}" (${path}), and --refresh is not set. Run \`catalog-sync generate --refresh\` to fetch ${src.url}.`
66
+ );
67
+ }
68
+ const { headers, missing } = resolveHeaders(src.headers);
69
+ if (missing.length > 0) {
70
+ if (existing !== void 0) {
71
+ process.stderr.write(
72
+ `catalog-sync: skipping refresh of "${src.id}" \u2014 missing env ${missing.join(", ")}; reusing committed snapshot.
73
+ `
74
+ );
75
+ return JSON.parse(existing);
76
+ }
77
+ throw new Error(
78
+ `catalog-sync: cannot refresh "${src.id}" \u2014 missing env ${missing.join(", ")} and no committed snapshot.`
79
+ );
80
+ }
81
+ const res = await fetch(src.url, {
82
+ method: src.method ?? "GET",
83
+ headers,
84
+ ...src.body !== void 0 ? { body: JSON.stringify(src.body) } : {}
85
+ });
86
+ if (!res.ok) {
87
+ throw new Error(
88
+ `catalog-sync: fetch ${src.url} failed: ${res.status} ${res.statusText}`
89
+ );
90
+ }
91
+ const text = await res.text();
92
+ const parsed = JSON.parse(text);
93
+ mkdirSync(dirname(path), { recursive: true });
94
+ writeFileSync(path, `${JSON.stringify(parsed, null, 2)}
95
+ `, "utf8");
96
+ return parsed;
97
+ }
98
+ };
99
+ const out = await gen.generate(ctx);
100
+ for (const [path, content] of Object.entries(out)) {
101
+ files[path] = content;
102
+ }
103
+ }
104
+ const root = repoRoot();
105
+ const changed = [];
106
+ for (const [relPath, content] of Object.entries(files)) {
107
+ const abs = join(root, relPath);
108
+ const existing = readIfExists(abs);
109
+ if (existing !== content) {
110
+ changed.push(relPath);
111
+ if (opts.write) {
112
+ mkdirSync(dirname(abs), { recursive: true });
113
+ writeFileSync(abs, content, "utf8");
114
+ }
115
+ }
116
+ }
117
+ return { files, changed };
118
+ }
119
+ var OPENROUTER_MODELS_URL = "https://openrouter.ai/api/v1/models";
120
+ var OUTPUT_PATH = "packages/model-catalog/src/llm/openrouter-routes.generated.ts";
121
+ var PricingSchema = z.object({
122
+ prompt: z.string().optional(),
123
+ completion: z.string().optional(),
124
+ input_cache_read: z.string().optional(),
125
+ input_cache_write: z.string().optional()
126
+ }).passthrough();
127
+ var ModelSchema = z.object({
128
+ id: z.string(),
129
+ pricing: PricingSchema.optional()
130
+ }).passthrough();
131
+ var SnapshotSchema = z.object({
132
+ data: z.array(ModelSchema)
133
+ });
134
+ function round6(n) {
135
+ return Math.round(n * 1e6) / 1e6;
136
+ }
137
+ function per1m(tokenPrice) {
138
+ if (tokenPrice === void 0) return void 0;
139
+ const n = Number(tokenPrice);
140
+ if (!Number.isFinite(n)) return void 0;
141
+ return round6(n * 1e6);
142
+ }
143
+ function fmt(n) {
144
+ if (!Number.isFinite(n)) return "0";
145
+ return `${round6(n)}`;
146
+ }
147
+ function vendorOf(id) {
148
+ if (!id.includes("/")) return id;
149
+ return id.split("/")[0] ?? id;
150
+ }
151
+ function serializeEntry(e) {
152
+ const fields = [
153
+ `inputPer1M: ${fmt(e.inputPer1M)}`,
154
+ `outputPer1M: ${fmt(e.outputPer1M)}`
155
+ ];
156
+ if (e.cacheReadMultiplier !== void 0) {
157
+ fields.push(`cacheReadMultiplier: ${fmt(e.cacheReadMultiplier)}`);
158
+ }
159
+ if (e.cacheWriteMultiplier !== void 0) {
160
+ fields.push(`cacheWriteMultiplier: ${fmt(e.cacheWriteMultiplier)}`);
161
+ }
162
+ fields.push(`vendor: ${JSON.stringify(e.vendor)}`);
163
+ fields.push(`provider: ${JSON.stringify(e.provider)}`);
164
+ return `{
165
+ ${fields.join(",\n ")},
166
+ }`;
167
+ }
168
+ function serializeFile(entries) {
169
+ const ids = Object.keys(entries).sort();
170
+ const providers = Array.from(new Set(ids.map(vendorOf))).sort();
171
+ const lines = [
172
+ "// AUTO-GENERATED by @agentproto/catalog-sync (llm:openrouter).",
173
+ "// Do not edit by hand \u2014 re-run `pnpm --filter @agentproto/catalog-sync generate`.",
174
+ `// Source: ${OPENROUTER_MODELS_URL}`,
175
+ "// Pricing carries provider USD (inputPer1M / outputPer1M) plus cache",
176
+ "// multipliers (cacheReadMultiplier / cacheWriteMultiplier) derived from the",
177
+ "// source's input_cache_read / input_cache_write per-token fields when present.",
178
+ "",
179
+ 'import type { LLMPricing } from "./catalog.js"',
180
+ "",
181
+ "export const OPENROUTER_ROUTES: Record<string, LLMPricing> = {"
182
+ ];
183
+ for (const id of ids) {
184
+ lines.push(` ${JSON.stringify(id)}: ${serializeEntry(entries[id])},`);
185
+ }
186
+ lines.push("}");
187
+ lines.push("");
188
+ lines.push("/** Provider slugs treated as OpenRouter routes by the picker. */");
189
+ lines.push("export const OPENROUTER_PROVIDERS: readonly string[] = [");
190
+ for (const p of providers) {
191
+ lines.push(` ${JSON.stringify(p)},`);
192
+ }
193
+ lines.push("]");
194
+ lines.push("");
195
+ return lines.join("\n");
196
+ }
197
+ async function generate(ctx) {
198
+ const src = sources[0];
199
+ if (!src) throw new Error("llm:openrouter: no source configured");
200
+ const parsed = SnapshotSchema.parse(await ctx.fetchSource(src));
201
+ const entries = {};
202
+ for (const model of parsed.data) {
203
+ const pricing = model.pricing;
204
+ if (!pricing) continue;
205
+ const inputPer1M = per1m(pricing.prompt);
206
+ const outputPer1M = per1m(pricing.completion);
207
+ if (inputPer1M === void 0 || outputPer1M === void 0) continue;
208
+ if (inputPer1M === 0 && outputPer1M === 0) continue;
209
+ const entry = {
210
+ inputPer1M,
211
+ outputPer1M,
212
+ vendor: vendorOf(model.id),
213
+ provider: "openrouter"
214
+ };
215
+ const cacheReadPer1M = per1m(pricing.input_cache_read);
216
+ const cacheWritePer1M = per1m(pricing.input_cache_write);
217
+ if (cacheReadPer1M !== void 0 && cacheReadPer1M > 0 && inputPer1M > 0) {
218
+ entry.cacheReadMultiplier = round6(cacheReadPer1M / inputPer1M);
219
+ }
220
+ if (cacheWritePer1M !== void 0 && cacheWritePer1M > 0 && inputPer1M > 0) {
221
+ entry.cacheWriteMultiplier = round6(cacheWritePer1M / inputPer1M);
222
+ }
223
+ entries[model.id] = entry;
224
+ }
225
+ return { [OUTPUT_PATH]: serializeFile(entries) };
226
+ }
227
+ var sources = [{ id: "llm-openrouter", url: OPENROUTER_MODELS_URL }];
228
+ var llmOpenRouterGenerator = defineGenerator({
229
+ name: "llm:openrouter",
230
+ modality: "llm",
231
+ sources,
232
+ generate
233
+ });
234
+
235
+ // src/generators/serialize-voices.ts
236
+ function serializeVoice(v) {
237
+ const lines = [" {"];
238
+ lines.push(` catalogId: ${JSON.stringify(v.catalogId)},`);
239
+ lines.push(` providerVoiceId: ${JSON.stringify(v.providerVoiceId)},`);
240
+ lines.push(` provider: ${JSON.stringify(v.provider)},`);
241
+ lines.push(` label: ${JSON.stringify(v.label)},`);
242
+ lines.push(` description: ${JSON.stringify(v.description)},`);
243
+ lines.push(` gender: ${JSON.stringify(v.gender)},`);
244
+ lines.push(` primaryLanguage: ${JSON.stringify(v.primaryLanguage)},`);
245
+ lines.push(
246
+ ` supportedLanguages: [${v.supportedLanguages.map((l) => JSON.stringify(l)).join(", ")}],`
247
+ );
248
+ if (v.quality !== void 0) lines.push(` quality: ${JSON.stringify(v.quality)},`);
249
+ if (v.featured !== void 0) lines.push(` featured: ${v.featured},`);
250
+ if (v.samplePath !== void 0) lines.push(` samplePath: ${JSON.stringify(v.samplePath)},`);
251
+ if (v.age !== void 0) lines.push(` age: ${JSON.stringify(v.age)},`);
252
+ lines.push(" },");
253
+ return lines.join("\n");
254
+ }
255
+ function serializeVoiceModule(generatorName, exportName, voices) {
256
+ const lines = [
257
+ `// Generated by @agentproto/catalog-sync generator ${generatorName}`,
258
+ "// DO NOT EDIT MANUALLY \u2014 regenerate with catalog-sync",
259
+ "",
260
+ 'import type { CatalogVoice } from "@agentproto/model-catalog/schema/voice"',
261
+ "",
262
+ `export const ${exportName}: readonly CatalogVoice[] = [`
263
+ ];
264
+ for (const v of voices) lines.push(serializeVoice(v));
265
+ lines.push("] as const");
266
+ lines.push("");
267
+ return lines.join("\n");
268
+ }
269
+
270
+ // src/generators/voice-elevenlabs.ts
271
+ var ELEVENLABS_SOURCE = {
272
+ id: "voice-elevenlabs",
273
+ url: "https://api.elevenlabs.io/v1/voices",
274
+ // Live refresh needs the account key; offline reads ignore this.
275
+ headers: { "xi-api-key": "env:ELEVENLABS_API_KEY" }
276
+ };
277
+ var OUTPUT_PATH2 = "packages/catalog-sync/generated/voice-elevenlabs.generated.ts";
278
+ var voiceElevenlabs = defineGenerator({
279
+ name: "voice:elevenlabs",
280
+ modality: "voice",
281
+ sources: [ELEVENLABS_SOURCE],
282
+ async generate(ctx) {
283
+ const snapshot = ElevenLabsVoicesSnapshotSchema.parse(
284
+ await ctx.fetchSource(ELEVENLABS_SOURCE)
285
+ );
286
+ const voices = mapElevenLabsVoices(snapshot);
287
+ return {
288
+ [OUTPUT_PATH2]: serializeVoiceModule(
289
+ "voice:elevenlabs",
290
+ "ELEVENLABS_VOICES",
291
+ voices
292
+ )
293
+ };
294
+ }
295
+ });
296
+ var MINIMAX_SOURCE = {
297
+ id: "voice-minimax",
298
+ url: "https://api.minimax.io/v1/get_voice",
299
+ // get_voice is a POST; live refresh needs the account key (Bearer). Without
300
+ // MINIMAX_API_KEY set, the framework reuses the committed snapshot.
301
+ method: "POST",
302
+ headers: {
303
+ Authorization: "Bearer env:MINIMAX_API_KEY",
304
+ "Content-Type": "application/json"
305
+ },
306
+ body: { voice_type: "system" }
307
+ };
308
+ var OUTPUT_PATH3 = "packages/catalog-sync/generated/voice-minimax.generated.ts";
309
+ var voiceMinimax = defineGenerator({
310
+ name: "voice:minimax",
311
+ modality: "voice",
312
+ sources: [MINIMAX_SOURCE],
313
+ async generate(ctx) {
314
+ const snapshot = MinimaxVoicesSnapshotSchema.parse(
315
+ await ctx.fetchSource(MINIMAX_SOURCE)
316
+ );
317
+ const voices = mapMinimaxVoices(snapshot);
318
+ return {
319
+ [OUTPUT_PATH3]: serializeVoiceModule(
320
+ "voice:minimax",
321
+ "MINIMAX_VOICES",
322
+ voices
323
+ )
324
+ };
325
+ }
326
+ });
327
+
328
+ // src/generators/image-replicate.ts
329
+ var PRICING = {
330
+ "nano-banana-pro": { costPerImage: 0.15, costTier: "high", baseCost: 0.15, creditCost: 10 },
331
+ "nano-banana-2": { costPerImage: 0.06, costTier: "medium", baseCost: 0.06, creditCost: 5 },
332
+ "nano-banana": { costPerImage: 0.04, costTier: "low", baseCost: 0.04, creditCost: 5 },
333
+ "flux-2-dev": { costPerImage: 0.03, costTier: "low", baseCost: 0.03, creditCost: 3 },
334
+ "flux-kontext-pro": { costPerImage: 0.04, costTier: "low", baseCost: 0.04, creditCost: 5 },
335
+ "flux-kontext-max": { costPerImage: 0.08, costTier: "medium", baseCost: 0.08, creditCost: 8 },
336
+ "flux-1.1-pro-ultra": { costPerImage: 0.06, costTier: "medium", baseCost: 0.06, creditCost: 8 },
337
+ "seedream-4": { costPerImage: 0.03, costTier: "low", baseCost: 0.03, creditCost: 3 },
338
+ "recraft-v3": { costPerImage: 0.04, costTier: "low", baseCost: 0.04, creditCost: 5 },
339
+ "image-01": { costPerImage: 0.02, costTier: "low", baseCost: 0.02, creditCost: 2 },
340
+ "gpt-image-1": { costPerImage: 0.04, costTier: "low", baseCost: 0.04, creditCost: 5 },
341
+ "ideogram-v3-turbo": { costPerImage: 0.03, costTier: "low", baseCost: 0.03, creditCost: 4 },
342
+ "flux-1.1-pro": { costPerImage: 0.04, costTier: "low", baseCost: 0.04, creditCost: 5 }
343
+ };
344
+ var AGENT_VISIBLE = /* @__PURE__ */ new Set([
345
+ "nano-banana-pro",
346
+ "nano-banana-2",
347
+ "nano-banana",
348
+ "flux-2-dev",
349
+ "flux-kontext-pro",
350
+ "flux-kontext-max",
351
+ "flux-1.1-pro-ultra",
352
+ "seedream-4",
353
+ "recraft-v3",
354
+ "image-01",
355
+ "gpt-image-1",
356
+ "ideogram-v3-turbo"
357
+ ]);
358
+ var ASPECT_RATIOS_DEFAULT = {
359
+ supported: ["1:1", "9:16", "16:9", "2:3", "3:2", "3:4", "4:3"],
360
+ default: "1:1"
361
+ };
362
+ var ASPECT_RATIOS_WIDE = {
363
+ supported: ["1:1", "9:16", "16:9", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4"],
364
+ default: "1:1"
365
+ };
366
+ var ASPECT_RATIOS_ULTRA = {
367
+ supported: ["1:1", "9:16", "16:9", "21:9", "9:21", "3:4", "4:3"],
368
+ default: "1:1"
369
+ };
370
+ var ASPECT_RATIOS_NBPRO = {
371
+ supported: [
372
+ "1:1",
373
+ "9:16",
374
+ "16:9",
375
+ "2:3",
376
+ "3:2",
377
+ "3:4",
378
+ "4:3",
379
+ "4:5",
380
+ "5:4",
381
+ "21:9"
382
+ ],
383
+ default: "match_input_image"
384
+ };
385
+ var ASPECT_RATIOS_NB2 = {
386
+ supported: [
387
+ "1:1",
388
+ "9:16",
389
+ "16:9",
390
+ "2:3",
391
+ "3:2",
392
+ "3:4",
393
+ "4:3",
394
+ "4:5",
395
+ "5:4"
396
+ ],
397
+ default: "match_input_image"
398
+ };
399
+ var ASPECT_RATIOS_SQUARE = {
400
+ supported: ["1:1"],
401
+ default: "1:1"
402
+ };
403
+ var MODEL_SPECS = {
404
+ "nano-banana-pro": {
405
+ id: "nano-banana-pro",
406
+ name: "Nano Banana Pro",
407
+ capabilities: { generate: true, edit: true },
408
+ referenceImages: { supported: true, fieldName: "image_input", maxCount: 14, singular: false },
409
+ aspectRatio: ASPECT_RATIOS_NBPRO,
410
+ output: "string"
411
+ },
412
+ "nano-banana-2": {
413
+ id: "nano-banana-2",
414
+ name: "Nano Banana 2",
415
+ capabilities: { generate: true, edit: true },
416
+ referenceImages: { supported: true, fieldName: "image_input", maxCount: 4, singular: false },
417
+ aspectRatio: ASPECT_RATIOS_NB2,
418
+ output: "string"
419
+ },
420
+ "nano-banana": {
421
+ id: "nano-banana",
422
+ name: "Nano Banana",
423
+ capabilities: { generate: true, edit: true },
424
+ referenceImages: { supported: true, fieldName: "image_input", maxCount: 4, singular: false },
425
+ aspectRatio: ASPECT_RATIOS_DEFAULT,
426
+ output: "string"
427
+ },
428
+ "flux-2-dev": {
429
+ id: "flux-2-dev",
430
+ name: "Flux 2 Dev",
431
+ capabilities: { generate: true, edit: true },
432
+ referenceImages: { supported: true, fieldName: "input_images", maxCount: 5, singular: false },
433
+ aspectRatio: ASPECT_RATIOS_WIDE,
434
+ output: "string"
435
+ },
436
+ "flux-kontext-pro": {
437
+ id: "flux-kontext-pro",
438
+ name: "Flux Kontext Pro",
439
+ capabilities: { generate: true, edit: true },
440
+ referenceImages: { supported: true, fieldName: "input_image", maxCount: 1, singular: true },
441
+ aspectRatio: ASPECT_RATIOS_DEFAULT,
442
+ output: "string"
443
+ },
444
+ "flux-kontext-max": {
445
+ id: "flux-kontext-max",
446
+ name: "Flux Kontext Max",
447
+ capabilities: { generate: true, edit: true },
448
+ referenceImages: { supported: true, fieldName: "input_image", maxCount: 1, singular: true },
449
+ aspectRatio: ASPECT_RATIOS_DEFAULT,
450
+ output: "string"
451
+ },
452
+ "flux-1.1-pro-ultra": {
453
+ id: "flux-1.1-pro-ultra",
454
+ name: "Flux 1.1 Pro Ultra",
455
+ capabilities: { generate: true, edit: false },
456
+ referenceImages: { supported: false, fieldName: "none", maxCount: 0, singular: false },
457
+ aspectRatio: ASPECT_RATIOS_ULTRA,
458
+ output: "string"
459
+ },
460
+ "seedream-4": {
461
+ id: "seedream-4",
462
+ name: "SeedReam 4",
463
+ capabilities: { generate: true, edit: true },
464
+ referenceImages: { supported: true, fieldName: "image_input", maxCount: 10, singular: false },
465
+ aspectRatio: ASPECT_RATIOS_DEFAULT,
466
+ output: "string"
467
+ },
468
+ "recraft-v3": {
469
+ id: "recraft",
470
+ name: "Recraft V3",
471
+ capabilities: { generate: true, edit: false },
472
+ referenceImages: { supported: false, fieldName: "none", maxCount: 0, singular: false },
473
+ aspectRatio: ASPECT_RATIOS_SQUARE,
474
+ output: "string"
475
+ },
476
+ "image-01": {
477
+ id: "minimax",
478
+ name: "MiniMax Image",
479
+ capabilities: { generate: true, edit: false },
480
+ referenceImages: { supported: false, fieldName: "none", maxCount: 0, singular: false },
481
+ aspectRatio: { supported: ["1:1", "9:16", "16:9", "3:4", "4:3"], default: "1:1" },
482
+ output: "array"
483
+ },
484
+ "gpt-image-1": {
485
+ id: "gpt-image-1",
486
+ name: "OpenAI GPT Image 1",
487
+ capabilities: { generate: true, edit: true },
488
+ referenceImages: { supported: true, fieldName: "input_image", maxCount: 1, singular: true },
489
+ aspectRatio: { supported: ["1:1", "2:3", "3:2"], default: "1:1" },
490
+ output: "string"
491
+ },
492
+ "ideogram-v3-turbo": {
493
+ id: "ideogram-v3",
494
+ name: "Ideogram v3",
495
+ capabilities: { generate: true, edit: false },
496
+ referenceImages: { supported: false, fieldName: "none", maxCount: 0, singular: false },
497
+ aspectRatio: { supported: ["1:1", "9:16", "16:9", "2:3", "3:2"], default: "1:1" },
498
+ output: "string"
499
+ },
500
+ "flux-1.1-pro": {
501
+ id: "flux",
502
+ name: "Flux 1.1 Pro",
503
+ capabilities: { generate: true, edit: false },
504
+ referenceImages: { supported: false, fieldName: "none", maxCount: 0, singular: false },
505
+ aspectRatio: { supported: ["1:1", "9:16", "16:9"], default: "1:1" },
506
+ output: "string"
507
+ }
508
+ };
509
+ function mapModel(raw) {
510
+ const providerId = `${raw.owner}/${raw.name}`;
511
+ const spec = MODEL_SPECS[raw.name] ?? {
512
+ id: raw.name,
513
+ name: raw.name,
514
+ capabilities: { generate: true, edit: false },
515
+ referenceImages: { supported: false, fieldName: "none", maxCount: 0, singular: false },
516
+ aspectRatio: ASPECT_RATIOS_DEFAULT,
517
+ output: "string"
518
+ };
519
+ const pricing = PRICING[raw.name] ?? {
520
+ costPerImage: 0.03,
521
+ costTier: "low",
522
+ baseCost: 0.03,
523
+ creditCost: 3
524
+ };
525
+ return {
526
+ id: spec.id,
527
+ name: spec.name,
528
+ providerId,
529
+ provider: raw.owner === "openai" ? "openai" : raw.owner === "minimax" ? "minimax" : "replicate",
530
+ capabilities: spec.capabilities,
531
+ referenceImages: spec.referenceImages,
532
+ aspectRatio: spec.aspectRatio,
533
+ output: spec.output,
534
+ pricing: {
535
+ costPerImage: pricing.costPerImage,
536
+ costTier: pricing.costTier,
537
+ billingUnit: "per_image",
538
+ baseCost: pricing.baseCost,
539
+ ...pricing.creditCost !== void 0 ? { creditCost: pricing.creditCost } : {},
540
+ ...pricing.overrideCreditCost !== void 0 ? { overrideCreditCost: pricing.overrideCreditCost } : {}
541
+ },
542
+ description: raw.description,
543
+ agentVisible: AGENT_VISIBLE.has(raw.name),
544
+ ...spec.triggerWord ? { triggerWord: spec.triggerWord } : {}
545
+ };
546
+ }
547
+ var REPLICATE_SOURCE = {
548
+ id: "image-replicate",
549
+ url: "https://api.replicate.com/v1/models?query=image+generation"
550
+ };
551
+ var imageReplicate = defineGenerator({
552
+ name: "image:replicate",
553
+ modality: "image",
554
+ sources: [REPLICATE_SOURCE],
555
+ async generate(ctx) {
556
+ const data = await ctx.fetchSource(REPLICATE_SOURCE);
557
+ const entries = data.models.map(mapModel);
558
+ const lines = [
559
+ "// Generated by @agentproto/catalog-sync generator image:replicate",
560
+ "// DO NOT EDIT MANUALLY \u2014 regenerate with catalog-sync",
561
+ "",
562
+ 'import type { ImageModelDefinition } from "@agentproto/model-catalog/image"',
563
+ "",
564
+ "export const REPLICATE_IMAGE_MODELS: Record<string, ImageModelDefinition> = {"
565
+ ];
566
+ for (const e of entries) {
567
+ const trigger = e.triggerWord ? `,
568
+ triggerWord: ${JSON.stringify(e.triggerWord)}` : "";
569
+ const creditCost = e.pricing.creditCost !== void 0 ? `,
570
+ creditCost: ${e.pricing.creditCost}` : "";
571
+ const override = e.pricing.overrideCreditCost !== void 0 ? `,
572
+ overrideCreditCost: ${e.pricing.overrideCreditCost}` : "";
573
+ lines.push(` ${JSON.stringify(e.id)}: {`);
574
+ lines.push(` id: ${JSON.stringify(e.id)},`);
575
+ lines.push(` name: ${JSON.stringify(e.name)},`);
576
+ lines.push(` providerId: ${JSON.stringify(e.providerId)},`);
577
+ lines.push(` provider: ${JSON.stringify(e.provider)},`);
578
+ lines.push(` capabilities: { generate: ${e.capabilities.generate}, edit: ${e.capabilities.edit}${e.capabilities.upscale ? `, upscale: ${e.capabilities.upscale}` : ""} },`);
579
+ lines.push(` referenceImages: {`);
580
+ lines.push(` supported: ${e.referenceImages.supported},`);
581
+ lines.push(` fieldName: ${JSON.stringify(e.referenceImages.fieldName)},`);
582
+ lines.push(` maxCount: ${e.referenceImages.maxCount},`);
583
+ lines.push(` singular: ${e.referenceImages.singular},`);
584
+ lines.push(` },`);
585
+ lines.push(` aspectRatio: {`);
586
+ lines.push(` supported: [${e.aspectRatio.supported.map((a) => JSON.stringify(a)).join(", ")}],`);
587
+ lines.push(` default: ${JSON.stringify(e.aspectRatio.default)},`);
588
+ lines.push(` },`);
589
+ lines.push(` output: ${JSON.stringify(e.output)},`);
590
+ lines.push(` pricing: {`);
591
+ lines.push(` costPerImage: ${e.pricing.costPerImage},`);
592
+ lines.push(` costTier: ${JSON.stringify(e.pricing.costTier)},`);
593
+ lines.push(` billingUnit: ${JSON.stringify(e.pricing.billingUnit)},`);
594
+ lines.push(` baseCost: ${e.pricing.baseCost},${creditCost}${override}`);
595
+ lines.push(` },`);
596
+ lines.push(` description: ${JSON.stringify(e.description)},`);
597
+ lines.push(` agentVisible: ${e.agentVisible},${trigger}`);
598
+ lines.push(` },`);
599
+ }
600
+ lines.push("}");
601
+ lines.push("");
602
+ const outputPath = "packages/catalog-sync/generated/image-replicate.generated.ts";
603
+ return { [outputPath]: lines.join("\n") };
604
+ }
605
+ });
606
+
607
+ export { defineGenerator, imageReplicate, llmOpenRouterGenerator, runGenerators, voiceElevenlabs, voiceMinimax };
608
+ //# sourceMappingURL=index.mjs.map
609
+ //# sourceMappingURL=index.mjs.map