@agentproto/catalog-sync 0.5.13 → 0.6.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.
package/dist/index.mjs CHANGED
@@ -142,7 +142,9 @@ function resolveHeaders(headers) {
142
142
  }
143
143
  var CATALOG_CHANGELOG_PATH = "packages/model-catalog/CATALOG-CHANGELOG.md";
144
144
  function isChangelogEligible(relPath) {
145
- return relPath.endsWith(".generated.ts");
145
+ if (!relPath.endsWith(".generated.ts")) return false;
146
+ if (relPath.startsWith("packages/catalog-sync/generated/")) return false;
147
+ return true;
146
148
  }
147
149
  async function runGenerators(gens, opts) {
148
150
  const files = {};
@@ -497,6 +499,259 @@ var llmRequestyGenerator = defineGenerator({
497
499
  sources: sources2,
498
500
  generate: generate2
499
501
  });
502
+ var MODELS_DEV_URL = "https://models.dev/api.json";
503
+ var ModelSchema3 = z.object({
504
+ id: z.string().optional(),
505
+ name: z.string().optional(),
506
+ family: z.string().optional(),
507
+ /** ISO `YYYY-MM-DD` already — no unix-seconds conversion (cf. Requesty). */
508
+ release_date: z.string().optional(),
509
+ provider: z.object({
510
+ /** Which AI-SDK package serves this model — the ONLY discriminator
511
+ * for the endpoint's three wire surfaces (see
512
+ * {@link anthropicSurfaceIds}). */
513
+ npm: z.string().optional()
514
+ }).passthrough().optional(),
515
+ cost: z.object({
516
+ input: z.number().optional(),
517
+ output: z.number().optional(),
518
+ cache_read: z.number().optional(),
519
+ cache_write: z.number().optional()
520
+ }).passthrough().optional()
521
+ }).passthrough();
522
+ var ProviderSchema = z.object({
523
+ id: z.string().optional(),
524
+ name: z.string().optional(),
525
+ /** The endpoint's base URL, e.g. `https://opencode.ai/zen/go/v1`. */
526
+ api: z.string().optional(),
527
+ doc: z.string().optional(),
528
+ env: z.array(z.string()).optional(),
529
+ npm: z.string().optional(),
530
+ models: z.record(z.string(), ModelSchema3).optional()
531
+ }).passthrough();
532
+ var SnapshotSchema3 = z.record(z.string(), ProviderSchema);
533
+ function round63(n) {
534
+ return Math.round(n * 1e6) / 1e6;
535
+ }
536
+ function fmt3(n) {
537
+ if (!Number.isFinite(n)) return "0";
538
+ return `${round63(n)}`;
539
+ }
540
+ function cacheMultiplier(cachePer1M, inputPer1M) {
541
+ if (cachePer1M === void 0 || !Number.isFinite(cachePer1M)) return void 0;
542
+ if (inputPer1M <= 0) return void 0;
543
+ return round63(cachePer1M / inputPer1M);
544
+ }
545
+ var VENDOR_BY_ID_PREFIX = [
546
+ [/^claude-/, "anthropic"],
547
+ [/^gemini-/, "google"],
548
+ [/^gpt-/, "openai"],
549
+ [/^grok-/, "x-ai"],
550
+ [/^glm-/, "z-ai"],
551
+ [/^kimi-/, "moonshotai"],
552
+ [/^deepseek-/, "deepseek"],
553
+ [/^minimax-/, "minimax"],
554
+ [/^qwen/, "qwen"],
555
+ [/^mimo-/, "xiaomi"],
556
+ [/^hy\d/, "tencent"],
557
+ [/^longcat-/, "meituan"],
558
+ [/^(ling|ring)-/, "inclusionai"],
559
+ [/^nemotron-/, "nvidia"],
560
+ [/^trinity-/, "arcee-ai"],
561
+ [/^laguna-/, "poolside"],
562
+ [/^north-/, "cohere"],
563
+ [/^muse-spark-/, "meta"]
564
+ ];
565
+ function vendorForOpencodeModelId(bareId) {
566
+ for (const [pattern, vendor] of VENDOR_BY_ID_PREFIX) {
567
+ if (pattern.test(bareId)) return vendor;
568
+ }
569
+ return "opencode";
570
+ }
571
+ function routeKey(provider, bareId) {
572
+ return `${provider}/${bareId}`;
573
+ }
574
+ function serializeEntry3(e) {
575
+ const fields = [
576
+ `inputPer1M: ${fmt3(e.inputPer1M)}`,
577
+ `outputPer1M: ${fmt3(e.outputPer1M)}`
578
+ ];
579
+ if (e.cacheReadMultiplier !== void 0) {
580
+ fields.push(`cacheReadMultiplier: ${fmt3(e.cacheReadMultiplier)}`);
581
+ }
582
+ if (e.cacheWriteMultiplier !== void 0) {
583
+ fields.push(`cacheWriteMultiplier: ${fmt3(e.cacheWriteMultiplier)}`);
584
+ }
585
+ if (e.addedAt !== void 0) {
586
+ fields.push(`addedAt: ${JSON.stringify(e.addedAt)}`);
587
+ }
588
+ fields.push(`vendor: ${JSON.stringify(e.vendor)}`);
589
+ fields.push(`provider: ${JSON.stringify(e.provider)}`);
590
+ return `{
591
+ ${fields.join(",\n ")},
592
+ }`;
593
+ }
594
+ var GO = {
595
+ providerKey: "opencode-go",
596
+ ledgerId: "llm-opencode-go",
597
+ generatorName: "llm:opencode-go",
598
+ outputPath: "packages/model-catalog/src/llm/opencode-go-routes.generated.ts",
599
+ routesConst: "OPENCODE_GO_ROUTES",
600
+ anthropicConst: "OPENCODE_GO_ANTHROPIC_MODELS",
601
+ label: "OpenCode Go"
602
+ };
603
+ var ZEN = {
604
+ providerKey: "opencode",
605
+ ledgerId: "llm-opencode-zen",
606
+ generatorName: "llm:opencode-zen",
607
+ outputPath: "packages/model-catalog/src/llm/opencode-zen-routes.generated.ts",
608
+ routesConst: "OPENCODE_ZEN_ROUTES",
609
+ anthropicConst: "OPENCODE_ZEN_ANTHROPIC_MODELS",
610
+ label: "OpenCode Zen"
611
+ };
612
+ function serializeFile3(endpoint, entries, anthropicIds) {
613
+ const keys = Object.keys(entries).sort();
614
+ const lines = [
615
+ `// AUTO-GENERATED by @agentproto/catalog-sync (${endpoint.generatorName}).`,
616
+ "// Do not edit by hand \u2014 re-run `pnpm --filter @agentproto/catalog-sync generate`.",
617
+ `// Source: ${MODELS_DEV_URL} (provider "${endpoint.providerKey}" \u2014 ${endpoint.label})`,
618
+ "// Prices come VERBATIM from the source's cost.input / cost.output, which",
619
+ "// models.dev already publishes as USD per 1M tokens (no per-token",
620
+ "// conversion, unlike the Requesty table). cacheReadMultiplier /",
621
+ "// cacheWriteMultiplier are cost.cache_read / cost.cache_write expressed",
622
+ "// relative to cost.input, and are omitted when the base input price is 0",
623
+ "// (every `-free` variant) because a free model has no cache discount.",
624
+ "// Zero-priced models are KEPT \u2014 on these endpoints zero is the truth, not",
625
+ "// a missing price.",
626
+ "// Keys are `<provider>/<bare-id>`, the form opencode's own config uses and",
627
+ "// the form the runtime derives the billing endpoint from; `vendor` is a",
628
+ "// heuristic attribution of the model's BUILDER and is metadata only.",
629
+ "// addedAt is the ISO date this id was first seen by a sync run \u2014 backfilled",
630
+ "// from the source's own `release_date`, then NEVER mutated; see",
631
+ "// packages/catalog-sync/src/added-at.ts and the package README.",
632
+ "",
633
+ 'import type { LLMPricing } from "./catalog.js"',
634
+ "",
635
+ `export const ${endpoint.routesConst}: Record<string, LLMPricing> = {`
636
+ ];
637
+ for (const key of keys) {
638
+ lines.push(` ${JSON.stringify(key)}: ${serializeEntry3(entries[key])},`);
639
+ }
640
+ lines.push("}");
641
+ lines.push("");
642
+ lines.push("/**");
643
+ lines.push(` * BARE ids on ${endpoint.label} whose wire surface is the Anthropic Messages`);
644
+ lines.push(' * API \u2014 the source\'s `provider.npm === "@ai-sdk/anthropic"`. These are the');
645
+ lines.push(" * ONLY ids reachable through the Anthropic-compatible gateway preset of the");
646
+ lines.push(" * same name (claude-code / claude-sdk); the rest of the endpoint's lineup");
647
+ lines.push(" * speaks OpenAI chat/completions or the OpenAI Responses API and has to go");
648
+ lines.push(" * through the opencode adapter instead. Bare (not `<provider>/<id>`) because");
649
+ lines.push(" * that is what an Anthropic client puts in `ANTHROPIC_MODEL` / on the wire.");
650
+ lines.push(" */");
651
+ lines.push(`export const ${endpoint.anthropicConst}: readonly string[] = [`);
652
+ for (const id of [...anthropicIds].sort()) {
653
+ lines.push(` ${JSON.stringify(id)},`);
654
+ }
655
+ lines.push("]");
656
+ lines.push("");
657
+ return lines.join("\n");
658
+ }
659
+ function projectSnapshot(providerKey, provider) {
660
+ const models = {};
661
+ for (const bareId of Object.keys(provider.models ?? {}).sort()) {
662
+ const model = provider.models?.[bareId];
663
+ if (!model) continue;
664
+ models[bareId] = {
665
+ ...model.id !== void 0 ? { id: model.id } : {},
666
+ ...model.name !== void 0 ? { name: model.name } : {},
667
+ ...model.family !== void 0 ? { family: model.family } : {},
668
+ ...model.release_date !== void 0 ? { release_date: model.release_date } : {},
669
+ ...model.provider?.npm !== void 0 ? { provider: { npm: model.provider.npm } } : {},
670
+ ...model.cost !== void 0 ? {
671
+ cost: {
672
+ ...model.cost.input !== void 0 ? { input: model.cost.input } : {},
673
+ ...model.cost.output !== void 0 ? { output: model.cost.output } : {},
674
+ ...model.cost.cache_read !== void 0 ? { cache_read: model.cost.cache_read } : {},
675
+ ...model.cost.cache_write !== void 0 ? { cache_write: model.cost.cache_write } : {}
676
+ }
677
+ } : {}
678
+ };
679
+ }
680
+ const projected = {
681
+ ...provider.id !== void 0 ? { id: provider.id } : {},
682
+ ...provider.name !== void 0 ? { name: provider.name } : {},
683
+ ...provider.api !== void 0 ? { api: provider.api } : {},
684
+ ...provider.doc !== void 0 ? { doc: provider.doc } : {},
685
+ ...provider.env !== void 0 ? { env: provider.env } : {},
686
+ ...provider.npm !== void 0 ? { npm: provider.npm } : {},
687
+ models
688
+ };
689
+ return `${JSON.stringify({ [providerKey]: projected }, null, 2)}
690
+ `;
691
+ }
692
+ function snapshotRelPath(ledgerId) {
693
+ return `packages/catalog-sync/snapshots/${ledgerId}.json`;
694
+ }
695
+ function anthropicSurfaceIds(models) {
696
+ return Object.entries(models).filter(([, model]) => model.provider?.npm === "@ai-sdk/anthropic").map(([bareId]) => bareId).sort();
697
+ }
698
+ async function generateFor(endpoint, source, ctx) {
699
+ const parsed = SnapshotSchema3.parse(await ctx.fetchSource(source));
700
+ const provider = parsed[endpoint.providerKey];
701
+ if (!provider) {
702
+ throw new Error(
703
+ `${endpoint.generatorName}: models.dev payload carries no "${endpoint.providerKey}" provider (source ${source.url}). Refusing to emit an empty route table.`
704
+ );
705
+ }
706
+ const models = provider.models ?? {};
707
+ const entries = {};
708
+ const releasedAt = {};
709
+ for (const [bareId, model] of Object.entries(models)) {
710
+ const inputPer1M = model.cost?.input;
711
+ const outputPer1M = model.cost?.output;
712
+ if (inputPer1M === void 0 || outputPer1M === void 0) continue;
713
+ if (!Number.isFinite(inputPer1M) || !Number.isFinite(outputPer1M)) continue;
714
+ const key = routeKey(endpoint.providerKey, bareId);
715
+ const entry = {
716
+ inputPer1M: round63(inputPer1M),
717
+ outputPer1M: round63(outputPer1M),
718
+ vendor: vendorForOpencodeModelId(bareId),
719
+ provider: endpoint.providerKey
720
+ };
721
+ const read = cacheMultiplier(model.cost?.cache_read, inputPer1M);
722
+ if (read !== void 0) entry.cacheReadMultiplier = read;
723
+ const write = cacheMultiplier(model.cost?.cache_write, inputPer1M);
724
+ if (write !== void 0) entry.cacheWriteMultiplier = write;
725
+ entries[key] = entry;
726
+ if (model.release_date !== void 0) releasedAt[key] = model.release_date;
727
+ }
728
+ const ledger = computeAddedAtLedger(
729
+ Object.keys(entries),
730
+ readLedger(endpoint.ledgerId),
731
+ releasedAt,
732
+ todayIso()
733
+ );
734
+ for (const [key, entry] of Object.entries(entries)) entry.addedAt = ledger[key];
735
+ return {
736
+ [endpoint.outputPath]: serializeFile3(endpoint, entries, anthropicSurfaceIds(models)),
737
+ [ledgerRelPath(endpoint.ledgerId)]: serializeLedger(ledger),
738
+ [snapshotRelPath(endpoint.ledgerId)]: projectSnapshot(endpoint.providerKey, provider)
739
+ };
740
+ }
741
+ var goSources = [{ id: GO.ledgerId, url: MODELS_DEV_URL }];
742
+ var zenSources = [{ id: ZEN.ledgerId, url: MODELS_DEV_URL }];
743
+ var llmOpencodeGoGenerator = defineGenerator({
744
+ name: GO.generatorName,
745
+ modality: "llm",
746
+ sources: goSources,
747
+ generate: (ctx) => generateFor(GO, goSources[0], ctx)
748
+ });
749
+ var llmOpencodeZenGenerator = defineGenerator({
750
+ name: ZEN.generatorName,
751
+ modality: "llm",
752
+ sources: zenSources,
753
+ generate: (ctx) => generateFor(ZEN, zenSources[0], ctx)
754
+ });
500
755
  var HUGGINGFACE_MODELS_URL = "https://router.huggingface.co/v1/models";
501
756
  var OUTPUT_PATH3 = "packages/model-catalog/src/llm/huggingface-routes.generated.ts";
502
757
  var HFProviderSchema = z.object({
@@ -514,7 +769,7 @@ var HFModelSchema = z.object({
514
769
  id: z.string(),
515
770
  providers: z.array(HFProviderSchema).optional()
516
771
  }).passthrough();
517
- var SnapshotSchema3 = z.object({
772
+ var SnapshotSchema4 = z.object({
518
773
  data: z.array(HFModelSchema)
519
774
  });
520
775
  function round4(n) {
@@ -536,7 +791,7 @@ function serializeProvider(p) {
536
791
  ${fields.join(",\n ")},
537
792
  }`;
538
793
  }
539
- function serializeEntry3(id, e) {
794
+ function serializeEntry4(id, e) {
540
795
  const providerLines = e.providers.map(serializeProvider).join(",\n");
541
796
  return [
542
797
  ` ${JSON.stringify(id)}: {`,
@@ -547,7 +802,7 @@ function serializeEntry3(id, e) {
547
802
  ` },`
548
803
  ].join("\n");
549
804
  }
550
- function serializeFile3(entries) {
805
+ function serializeFile4(entries) {
551
806
  const ids = Object.keys(entries).sort();
552
807
  const lines = [
553
808
  "// AUTO-GENERATED by @agentproto/catalog-sync (llm:huggingface).",
@@ -580,7 +835,7 @@ function serializeFile3(entries) {
580
835
  "export const HUGGINGFACE_ROUTES: Record<string, HuggingFaceRoute> = {"
581
836
  ];
582
837
  for (const id of ids) {
583
- lines.push(serializeEntry3(id, entries[id]));
838
+ lines.push(serializeEntry4(id, entries[id]));
584
839
  }
585
840
  lines.push("}");
586
841
  lines.push("");
@@ -589,7 +844,7 @@ function serializeFile3(entries) {
589
844
  async function generate3(ctx) {
590
845
  const src = sources3[0];
591
846
  if (!src) throw new Error("llm:huggingface: no source configured");
592
- const parsed = SnapshotSchema3.parse(await ctx.fetchSource(src));
847
+ const parsed = SnapshotSchema4.parse(await ctx.fetchSource(src));
593
848
  const entries = {};
594
849
  for (const model of parsed.data) {
595
850
  const liveProviders = (model.providers ?? []).filter((p) => p.status === "live");
@@ -610,7 +865,7 @@ async function generate3(ctx) {
610
865
  }).sort((a, b) => a.provider.localeCompare(b.provider));
611
866
  entries[model.id] = { wireId: model.id, providers };
612
867
  }
613
- return { [OUTPUT_PATH3]: serializeFile3(entries) };
868
+ return { [OUTPUT_PATH3]: serializeFile4(entries) };
614
869
  }
615
870
  var sources3 = [
616
871
  {
@@ -717,8 +972,28 @@ var voiceMinimax = defineGenerator({
717
972
  };
718
973
  }
719
974
  });
720
-
721
- // src/generators/image-replicate.ts
975
+ var ReplicateModelSchema = z.object({
976
+ owner: z.string(),
977
+ name: z.string(),
978
+ description: z.string().nullable(),
979
+ visibility: z.string(),
980
+ run_count: z.number(),
981
+ cover_image_url: z.string().nullable(),
982
+ latest_version: z.object({
983
+ id: z.string(),
984
+ created_at: z.string(),
985
+ openapi_schema: z.any()
986
+ })
987
+ }).passthrough();
988
+ var ReplicateSnapshotSchema = z.object({
989
+ // DRF-paginated shape (live API)
990
+ results: z.array(ReplicateModelSchema).optional(),
991
+ next: z.string().nullable().optional(),
992
+ previous: z.string().nullable().optional(),
993
+ // Hand-authored fixture shape (committed snapshot)
994
+ _meta: z.record(z.string(), z.unknown()).optional(),
995
+ models: z.array(ReplicateModelSchema).optional()
996
+ }).passthrough();
722
997
  var PRICING = {
723
998
  "nano-banana-pro": { costPerImage: 0.15, costTier: "high", baseCost: 0.15, creditCost: 10 },
724
999
  "nano-banana-2": { costPerImage: 0.06, costTier: "medium", baseCost: 0.06, creditCost: 5 },
@@ -932,14 +1207,14 @@ function mapModel(raw) {
932
1207
  ...pricing.creditCost !== void 0 ? { creditCost: pricing.creditCost } : {},
933
1208
  ...pricing.overrideCreditCost !== void 0 ? { overrideCreditCost: pricing.overrideCreditCost } : {}
934
1209
  },
935
- description: raw.description,
1210
+ description: raw.description ?? "",
936
1211
  agentVisible: AGENT_VISIBLE.has(raw.name),
937
1212
  ...spec.triggerWord ? { triggerWord: spec.triggerWord } : {}
938
1213
  };
939
1214
  }
940
1215
  var REPLICATE_SOURCE = {
941
1216
  id: "image-replicate",
942
- url: "https://api.replicate.com/v1/models?query=image+generation",
1217
+ url: "https://api.replicate.com/v1/collections/text-to-image",
943
1218
  headers: { Authorization: "Bearer env:REPLICATE_API_TOKEN" }
944
1219
  };
945
1220
  var imageReplicate = defineGenerator({
@@ -947,8 +1222,22 @@ var imageReplicate = defineGenerator({
947
1222
  modality: "image",
948
1223
  sources: [REPLICATE_SOURCE],
949
1224
  async generate(ctx) {
950
- const data = await ctx.fetchSource(REPLICATE_SOURCE);
951
- const entries = data.models.map(mapModel);
1225
+ const raw = await ctx.fetchSource(REPLICATE_SOURCE);
1226
+ const data = ReplicateSnapshotSchema.parse(raw);
1227
+ const models = data.results ?? data.models;
1228
+ if (!models) {
1229
+ throw new Error(
1230
+ "Replicate snapshot has neither `results` nor `models` array \u2014 invalid shape"
1231
+ );
1232
+ }
1233
+ const curatedModels = models.filter((m) => MODEL_SPECS[m.name]);
1234
+ if (curatedModels.length === 0) {
1235
+ const sampleNames = [...AGENT_VISIBLE].slice(0, 3).join(", ");
1236
+ throw new Error(
1237
+ `image:replicate: none of the curated models (${sampleNames}\u2026) present in source payload (${models.length} entries) \u2014 API shape or roster drift`
1238
+ );
1239
+ }
1240
+ const entries = curatedModels.map(mapModel);
952
1241
  const lines = [
953
1242
  "// Generated by @agentproto/catalog-sync generator image:replicate",
954
1243
  "// DO NOT EDIT MANUALLY \u2014 regenerate with catalog-sync",
@@ -1156,6 +1445,6 @@ var OPENAI_LLM_SOURCE = {
1156
1445
  };
1157
1446
  var OPENAI_SOURCES = [OPENAI_LLM_SOURCE];
1158
1447
 
1159
- export { CATALOG_CHANGELOG_HEADER, CATALOG_CHANGELOG_PATH, OPENAI_LLM_SOURCE, OPENAI_SOURCES, appendChangelog, computeAddedAtLedger, defineGenerator, diffModelIds, extractRecordIds, imageReplicate, isoDateFromUnixSeconds, ledgerAbsPath, ledgerRelPath, llmHuggingfaceGenerator, llmOpenRouterGenerator, llmRequestyGenerator, readLedger, refreshSources, renderChangelogSection, reviewedRefresh, runGenerators, serializeLedger, todayIso, voiceElevenlabs, voiceMinimax };
1448
+ export { CATALOG_CHANGELOG_HEADER, CATALOG_CHANGELOG_PATH, OPENAI_LLM_SOURCE, OPENAI_SOURCES, appendChangelog, computeAddedAtLedger, defineGenerator, diffModelIds, extractRecordIds, imageReplicate, isoDateFromUnixSeconds, ledgerAbsPath, ledgerRelPath, llmHuggingfaceGenerator, llmOpenRouterGenerator, llmOpencodeGoGenerator, llmOpencodeZenGenerator, llmRequestyGenerator, readLedger, refreshSources, renderChangelogSection, reviewedRefresh, runGenerators, serializeLedger, todayIso, voiceElevenlabs, voiceMinimax };
1160
1449
  //# sourceMappingURL=index.mjs.map
1161
1450
  //# sourceMappingURL=index.mjs.map