@agentproto/catalog-sync 0.5.13 → 0.6.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/bin.mjs CHANGED
@@ -327,6 +327,259 @@ var llmRequestyGenerator = defineGenerator({
327
327
  sources: sources2,
328
328
  generate: generate2
329
329
  });
330
+ var MODELS_DEV_URL = "https://models.dev/api.json";
331
+ var ModelSchema3 = z.object({
332
+ id: z.string().optional(),
333
+ name: z.string().optional(),
334
+ family: z.string().optional(),
335
+ /** ISO `YYYY-MM-DD` already — no unix-seconds conversion (cf. Requesty). */
336
+ release_date: z.string().optional(),
337
+ provider: z.object({
338
+ /** Which AI-SDK package serves this model — the ONLY discriminator
339
+ * for the endpoint's three wire surfaces (see
340
+ * {@link anthropicSurfaceIds}). */
341
+ npm: z.string().optional()
342
+ }).passthrough().optional(),
343
+ cost: z.object({
344
+ input: z.number().optional(),
345
+ output: z.number().optional(),
346
+ cache_read: z.number().optional(),
347
+ cache_write: z.number().optional()
348
+ }).passthrough().optional()
349
+ }).passthrough();
350
+ var ProviderSchema = z.object({
351
+ id: z.string().optional(),
352
+ name: z.string().optional(),
353
+ /** The endpoint's base URL, e.g. `https://opencode.ai/zen/go/v1`. */
354
+ api: z.string().optional(),
355
+ doc: z.string().optional(),
356
+ env: z.array(z.string()).optional(),
357
+ npm: z.string().optional(),
358
+ models: z.record(z.string(), ModelSchema3).optional()
359
+ }).passthrough();
360
+ var SnapshotSchema3 = z.record(z.string(), ProviderSchema);
361
+ function round63(n) {
362
+ return Math.round(n * 1e6) / 1e6;
363
+ }
364
+ function fmt3(n) {
365
+ if (!Number.isFinite(n)) return "0";
366
+ return `${round63(n)}`;
367
+ }
368
+ function cacheMultiplier(cachePer1M, inputPer1M) {
369
+ if (cachePer1M === void 0 || !Number.isFinite(cachePer1M)) return void 0;
370
+ if (inputPer1M <= 0) return void 0;
371
+ return round63(cachePer1M / inputPer1M);
372
+ }
373
+ var VENDOR_BY_ID_PREFIX = [
374
+ [/^claude-/, "anthropic"],
375
+ [/^gemini-/, "google"],
376
+ [/^gpt-/, "openai"],
377
+ [/^grok-/, "x-ai"],
378
+ [/^glm-/, "z-ai"],
379
+ [/^kimi-/, "moonshotai"],
380
+ [/^deepseek-/, "deepseek"],
381
+ [/^minimax-/, "minimax"],
382
+ [/^qwen/, "qwen"],
383
+ [/^mimo-/, "xiaomi"],
384
+ [/^hy\d/, "tencent"],
385
+ [/^longcat-/, "meituan"],
386
+ [/^(ling|ring)-/, "inclusionai"],
387
+ [/^nemotron-/, "nvidia"],
388
+ [/^trinity-/, "arcee-ai"],
389
+ [/^laguna-/, "poolside"],
390
+ [/^north-/, "cohere"],
391
+ [/^muse-spark-/, "meta"]
392
+ ];
393
+ function vendorForOpencodeModelId(bareId) {
394
+ for (const [pattern, vendor] of VENDOR_BY_ID_PREFIX) {
395
+ if (pattern.test(bareId)) return vendor;
396
+ }
397
+ return "opencode";
398
+ }
399
+ function routeKey(provider, bareId) {
400
+ return `${provider}/${bareId}`;
401
+ }
402
+ function serializeEntry3(e) {
403
+ const fields = [
404
+ `inputPer1M: ${fmt3(e.inputPer1M)}`,
405
+ `outputPer1M: ${fmt3(e.outputPer1M)}`
406
+ ];
407
+ if (e.cacheReadMultiplier !== void 0) {
408
+ fields.push(`cacheReadMultiplier: ${fmt3(e.cacheReadMultiplier)}`);
409
+ }
410
+ if (e.cacheWriteMultiplier !== void 0) {
411
+ fields.push(`cacheWriteMultiplier: ${fmt3(e.cacheWriteMultiplier)}`);
412
+ }
413
+ if (e.addedAt !== void 0) {
414
+ fields.push(`addedAt: ${JSON.stringify(e.addedAt)}`);
415
+ }
416
+ fields.push(`vendor: ${JSON.stringify(e.vendor)}`);
417
+ fields.push(`provider: ${JSON.stringify(e.provider)}`);
418
+ return `{
419
+ ${fields.join(",\n ")},
420
+ }`;
421
+ }
422
+ var GO = {
423
+ providerKey: "opencode-go",
424
+ ledgerId: "llm-opencode-go",
425
+ generatorName: "llm:opencode-go",
426
+ outputPath: "packages/model-catalog/src/llm/opencode-go-routes.generated.ts",
427
+ routesConst: "OPENCODE_GO_ROUTES",
428
+ anthropicConst: "OPENCODE_GO_ANTHROPIC_MODELS",
429
+ label: "OpenCode Go"
430
+ };
431
+ var ZEN = {
432
+ providerKey: "opencode",
433
+ ledgerId: "llm-opencode-zen",
434
+ generatorName: "llm:opencode-zen",
435
+ outputPath: "packages/model-catalog/src/llm/opencode-zen-routes.generated.ts",
436
+ routesConst: "OPENCODE_ZEN_ROUTES",
437
+ anthropicConst: "OPENCODE_ZEN_ANTHROPIC_MODELS",
438
+ label: "OpenCode Zen"
439
+ };
440
+ function serializeFile3(endpoint, entries, anthropicIds) {
441
+ const keys = Object.keys(entries).sort();
442
+ const lines = [
443
+ `// AUTO-GENERATED by @agentproto/catalog-sync (${endpoint.generatorName}).`,
444
+ "// Do not edit by hand \u2014 re-run `pnpm --filter @agentproto/catalog-sync generate`.",
445
+ `// Source: ${MODELS_DEV_URL} (provider "${endpoint.providerKey}" \u2014 ${endpoint.label})`,
446
+ "// Prices come VERBATIM from the source's cost.input / cost.output, which",
447
+ "// models.dev already publishes as USD per 1M tokens (no per-token",
448
+ "// conversion, unlike the Requesty table). cacheReadMultiplier /",
449
+ "// cacheWriteMultiplier are cost.cache_read / cost.cache_write expressed",
450
+ "// relative to cost.input, and are omitted when the base input price is 0",
451
+ "// (every `-free` variant) because a free model has no cache discount.",
452
+ "// Zero-priced models are KEPT \u2014 on these endpoints zero is the truth, not",
453
+ "// a missing price.",
454
+ "// Keys are `<provider>/<bare-id>`, the form opencode's own config uses and",
455
+ "// the form the runtime derives the billing endpoint from; `vendor` is a",
456
+ "// heuristic attribution of the model's BUILDER and is metadata only.",
457
+ "// addedAt is the ISO date this id was first seen by a sync run \u2014 backfilled",
458
+ "// from the source's own `release_date`, then NEVER mutated; see",
459
+ "// packages/catalog-sync/src/added-at.ts and the package README.",
460
+ "",
461
+ 'import type { LLMPricing } from "./catalog.js"',
462
+ "",
463
+ `export const ${endpoint.routesConst}: Record<string, LLMPricing> = {`
464
+ ];
465
+ for (const key of keys) {
466
+ lines.push(` ${JSON.stringify(key)}: ${serializeEntry3(entries[key])},`);
467
+ }
468
+ lines.push("}");
469
+ lines.push("");
470
+ lines.push("/**");
471
+ lines.push(` * BARE ids on ${endpoint.label} whose wire surface is the Anthropic Messages`);
472
+ lines.push(' * API \u2014 the source\'s `provider.npm === "@ai-sdk/anthropic"`. These are the');
473
+ lines.push(" * ONLY ids reachable through the Anthropic-compatible gateway preset of the");
474
+ lines.push(" * same name (claude-code / claude-sdk); the rest of the endpoint's lineup");
475
+ lines.push(" * speaks OpenAI chat/completions or the OpenAI Responses API and has to go");
476
+ lines.push(" * through the opencode adapter instead. Bare (not `<provider>/<id>`) because");
477
+ lines.push(" * that is what an Anthropic client puts in `ANTHROPIC_MODEL` / on the wire.");
478
+ lines.push(" */");
479
+ lines.push(`export const ${endpoint.anthropicConst}: readonly string[] = [`);
480
+ for (const id of [...anthropicIds].sort()) {
481
+ lines.push(` ${JSON.stringify(id)},`);
482
+ }
483
+ lines.push("]");
484
+ lines.push("");
485
+ return lines.join("\n");
486
+ }
487
+ function projectSnapshot(providerKey, provider) {
488
+ const models = {};
489
+ for (const bareId of Object.keys(provider.models ?? {}).sort()) {
490
+ const model = provider.models?.[bareId];
491
+ if (!model) continue;
492
+ models[bareId] = {
493
+ ...model.id !== void 0 ? { id: model.id } : {},
494
+ ...model.name !== void 0 ? { name: model.name } : {},
495
+ ...model.family !== void 0 ? { family: model.family } : {},
496
+ ...model.release_date !== void 0 ? { release_date: model.release_date } : {},
497
+ ...model.provider?.npm !== void 0 ? { provider: { npm: model.provider.npm } } : {},
498
+ ...model.cost !== void 0 ? {
499
+ cost: {
500
+ ...model.cost.input !== void 0 ? { input: model.cost.input } : {},
501
+ ...model.cost.output !== void 0 ? { output: model.cost.output } : {},
502
+ ...model.cost.cache_read !== void 0 ? { cache_read: model.cost.cache_read } : {},
503
+ ...model.cost.cache_write !== void 0 ? { cache_write: model.cost.cache_write } : {}
504
+ }
505
+ } : {}
506
+ };
507
+ }
508
+ const projected = {
509
+ ...provider.id !== void 0 ? { id: provider.id } : {},
510
+ ...provider.name !== void 0 ? { name: provider.name } : {},
511
+ ...provider.api !== void 0 ? { api: provider.api } : {},
512
+ ...provider.doc !== void 0 ? { doc: provider.doc } : {},
513
+ ...provider.env !== void 0 ? { env: provider.env } : {},
514
+ ...provider.npm !== void 0 ? { npm: provider.npm } : {},
515
+ models
516
+ };
517
+ return `${JSON.stringify({ [providerKey]: projected }, null, 2)}
518
+ `;
519
+ }
520
+ function snapshotRelPath(ledgerId) {
521
+ return `packages/catalog-sync/snapshots/${ledgerId}.json`;
522
+ }
523
+ function anthropicSurfaceIds(models) {
524
+ return Object.entries(models).filter(([, model]) => model.provider?.npm === "@ai-sdk/anthropic").map(([bareId]) => bareId).sort();
525
+ }
526
+ async function generateFor(endpoint, source, ctx) {
527
+ const parsed = SnapshotSchema3.parse(await ctx.fetchSource(source));
528
+ const provider = parsed[endpoint.providerKey];
529
+ if (!provider) {
530
+ throw new Error(
531
+ `${endpoint.generatorName}: models.dev payload carries no "${endpoint.providerKey}" provider (source ${source.url}). Refusing to emit an empty route table.`
532
+ );
533
+ }
534
+ const models = provider.models ?? {};
535
+ const entries = {};
536
+ const releasedAt = {};
537
+ for (const [bareId, model] of Object.entries(models)) {
538
+ const inputPer1M = model.cost?.input;
539
+ const outputPer1M = model.cost?.output;
540
+ if (inputPer1M === void 0 || outputPer1M === void 0) continue;
541
+ if (!Number.isFinite(inputPer1M) || !Number.isFinite(outputPer1M)) continue;
542
+ const key = routeKey(endpoint.providerKey, bareId);
543
+ const entry = {
544
+ inputPer1M: round63(inputPer1M),
545
+ outputPer1M: round63(outputPer1M),
546
+ vendor: vendorForOpencodeModelId(bareId),
547
+ provider: endpoint.providerKey
548
+ };
549
+ const read = cacheMultiplier(model.cost?.cache_read, inputPer1M);
550
+ if (read !== void 0) entry.cacheReadMultiplier = read;
551
+ const write = cacheMultiplier(model.cost?.cache_write, inputPer1M);
552
+ if (write !== void 0) entry.cacheWriteMultiplier = write;
553
+ entries[key] = entry;
554
+ if (model.release_date !== void 0) releasedAt[key] = model.release_date;
555
+ }
556
+ const ledger = computeAddedAtLedger(
557
+ Object.keys(entries),
558
+ readLedger(endpoint.ledgerId),
559
+ releasedAt,
560
+ todayIso()
561
+ );
562
+ for (const [key, entry] of Object.entries(entries)) entry.addedAt = ledger[key];
563
+ return {
564
+ [endpoint.outputPath]: serializeFile3(endpoint, entries, anthropicSurfaceIds(models)),
565
+ [ledgerRelPath(endpoint.ledgerId)]: serializeLedger(ledger),
566
+ [snapshotRelPath(endpoint.ledgerId)]: projectSnapshot(endpoint.providerKey, provider)
567
+ };
568
+ }
569
+ var goSources = [{ id: GO.ledgerId, url: MODELS_DEV_URL }];
570
+ var zenSources = [{ id: ZEN.ledgerId, url: MODELS_DEV_URL }];
571
+ var llmOpencodeGoGenerator = defineGenerator({
572
+ name: GO.generatorName,
573
+ modality: "llm",
574
+ sources: goSources,
575
+ generate: (ctx) => generateFor(GO, goSources[0], ctx)
576
+ });
577
+ var llmOpencodeZenGenerator = defineGenerator({
578
+ name: ZEN.generatorName,
579
+ modality: "llm",
580
+ sources: zenSources,
581
+ generate: (ctx) => generateFor(ZEN, zenSources[0], ctx)
582
+ });
330
583
  var HUGGINGFACE_MODELS_URL = "https://router.huggingface.co/v1/models";
331
584
  var OUTPUT_PATH3 = "packages/model-catalog/src/llm/huggingface-routes.generated.ts";
332
585
  var HFProviderSchema = z.object({
@@ -344,7 +597,7 @@ var HFModelSchema = z.object({
344
597
  id: z.string(),
345
598
  providers: z.array(HFProviderSchema).optional()
346
599
  }).passthrough();
347
- var SnapshotSchema3 = z.object({
600
+ var SnapshotSchema4 = z.object({
348
601
  data: z.array(HFModelSchema)
349
602
  });
350
603
  function round4(n) {
@@ -366,7 +619,7 @@ function serializeProvider(p) {
366
619
  ${fields.join(",\n ")},
367
620
  }`;
368
621
  }
369
- function serializeEntry3(id, e) {
622
+ function serializeEntry4(id, e) {
370
623
  const providerLines = e.providers.map(serializeProvider).join(",\n");
371
624
  return [
372
625
  ` ${JSON.stringify(id)}: {`,
@@ -377,7 +630,7 @@ function serializeEntry3(id, e) {
377
630
  ` },`
378
631
  ].join("\n");
379
632
  }
380
- function serializeFile3(entries) {
633
+ function serializeFile4(entries) {
381
634
  const ids = Object.keys(entries).sort();
382
635
  const lines = [
383
636
  "// AUTO-GENERATED by @agentproto/catalog-sync (llm:huggingface).",
@@ -410,7 +663,7 @@ function serializeFile3(entries) {
410
663
  "export const HUGGINGFACE_ROUTES: Record<string, HuggingFaceRoute> = {"
411
664
  ];
412
665
  for (const id of ids) {
413
- lines.push(serializeEntry3(id, entries[id]));
666
+ lines.push(serializeEntry4(id, entries[id]));
414
667
  }
415
668
  lines.push("}");
416
669
  lines.push("");
@@ -419,7 +672,7 @@ function serializeFile3(entries) {
419
672
  async function generate3(ctx) {
420
673
  const src = sources3[0];
421
674
  if (!src) throw new Error("llm:huggingface: no source configured");
422
- const parsed = SnapshotSchema3.parse(await ctx.fetchSource(src));
675
+ const parsed = SnapshotSchema4.parse(await ctx.fetchSource(src));
423
676
  const entries = {};
424
677
  for (const model of parsed.data) {
425
678
  const liveProviders = (model.providers ?? []).filter((p) => p.status === "live");
@@ -440,7 +693,7 @@ async function generate3(ctx) {
440
693
  }).sort((a, b) => a.provider.localeCompare(b.provider));
441
694
  entries[model.id] = { wireId: model.id, providers };
442
695
  }
443
- return { [OUTPUT_PATH3]: serializeFile3(entries) };
696
+ return { [OUTPUT_PATH3]: serializeFile4(entries) };
444
697
  }
445
698
  var sources3 = [
446
699
  {
@@ -502,14 +755,14 @@ var OpenRouterModelSchema = z.object({
502
755
  top_provider: z.object({ max_completion_tokens: z.number().nullable().optional() }).passthrough().optional()
503
756
  }).passthrough();
504
757
  var OpenRouterSnapshotSchema = z.object({ data: z.array(OpenRouterModelSchema) });
505
- function serializeEntry4(e) {
758
+ function serializeEntry5(e) {
506
759
  const fields = [`contextWindow: ${e.contextWindow}`];
507
760
  if (e.maxOutput !== void 0) fields.push(`maxOutput: ${e.maxOutput}`);
508
761
  if (e.displayName !== void 0) fields.push(`displayName: ${JSON.stringify(e.displayName)}`);
509
762
  fields.push(`provider: ${JSON.stringify(e.provider)}`);
510
763
  return `{ ${fields.join(", ")} }`;
511
764
  }
512
- function serializeFile4(entries) {
765
+ function serializeFile5(entries) {
513
766
  const ids = Object.keys(entries).sort();
514
767
  const lines = [
515
768
  "// AUTO-GENERATED by @agentproto/catalog-sync (llm:context-windows).",
@@ -534,7 +787,7 @@ function serializeFile4(entries) {
534
787
  "export const CONTEXT_WINDOWS: Record<string, ContextWindowEntry> = {"
535
788
  ];
536
789
  for (const id of ids) {
537
- lines.push(` ${JSON.stringify(id)}: ${serializeEntry4(entries[id])},`);
790
+ lines.push(` ${JSON.stringify(id)}: ${serializeEntry5(entries[id])},`);
538
791
  }
539
792
  lines.push("}");
540
793
  lines.push("");
@@ -624,7 +877,7 @@ async function generate4(ctx) {
624
877
  };
625
878
  }
626
879
  }
627
- return { [OUTPUT_PATH4]: serializeFile4(entries) };
880
+ return { [OUTPUT_PATH4]: serializeFile5(entries) };
628
881
  }
629
882
  var sources4 = [
630
883
  {
@@ -1129,7 +1382,9 @@ function resolveHeaders(headers) {
1129
1382
  }
1130
1383
  var CATALOG_CHANGELOG_PATH = "packages/model-catalog/CATALOG-CHANGELOG.md";
1131
1384
  function isChangelogEligible(relPath) {
1132
- return relPath.endsWith(".generated.ts");
1385
+ if (!relPath.endsWith(".generated.ts")) return false;
1386
+ if (relPath.startsWith("packages/catalog-sync/generated/")) return false;
1387
+ return true;
1133
1388
  }
1134
1389
  async function runGenerators(gens, opts) {
1135
1390
  const files2 = {};
@@ -1241,6 +1496,8 @@ var check = flags.has("--check");
1241
1496
  var generators = [
1242
1497
  llmOpenRouterGenerator,
1243
1498
  llmRequestyGenerator,
1499
+ llmOpencodeGoGenerator,
1500
+ llmOpencodeZenGenerator,
1244
1501
  llmHuggingfaceGenerator,
1245
1502
  llmContextWindowsGenerator,
1246
1503
  voiceElevenlabs,