@agentproto/catalog-sync

中文文档
0.9.1发布于 2026/11/06Apache-2.0TypeScriptES Module构建来源已验证近 30 天下载 1795

Build-time generator framework for @agentproto/model-catalog. Generates *.generated.ts from pinned provider sources (LLM, image, video, audio, voice).

原始使用文档
文档目录9 节
  1. Contract
  2. Flow
  3. CLI
  4. addedAt convention
  5. CATALOG-CHANGELOG.md
  6. Generators
  7. llm:openrouter
  8. llm:requesty
  9. llm:context-windows

@agentproto/catalog-sync

Build-time generator framework for @agentproto/model-catalog. Catalog data (prices, model lists) is generated from pinned provider sources, not hand-committed — every *.generated.ts is reproducible from a committed snapshot, and CI catches drift via --check.

Contract

// src/types.ts — FROZEN
interface CatalogSource { id: string; url: string }
interface GeneratorContext {
  fetchSource(src: CatalogSource): Promise<unknown>  // snapshot-first; refresh fetches + writes
  refresh: boolean
}
type GeneratedFiles = Record<string, string>  // repo-relative path → TS source text
interface CatalogGenerator {
  name: string                 // "llm:openrouter"
  modality: "llm" | "image" | "video" | "audio" | "voice"
  sources: CatalogSource[]
  generate(ctx: GeneratorContext): Promise<GeneratedFiles>
}
function defineGenerator(g: CatalogGenerator): CatalogGenerator

A sibling agent builds provider generators against this surface. Adding new generators is the extension path; editing types.ts is not.

Flow

provider API ──(generate --refresh)──▶ snapshots/<id>.json   ← committed, deterministic
                                              │
                            generate (offline) ▼
                                          *.generated.ts   ← drop-in for model-catalog
  • Offline by default. generate reads snapshots/<id>.json. Tests and CI never hit the network.
  • Network only behind --refresh, which fetches each source's pinned URL and writes the snapshot for the next offline run.

CLI

pnpm --filter @agentproto/catalog-sync generate          # write changed files
pnpm --filter @agentproto/catalog-sync generate --check  # diff vs committed; exit 1 on drift (CI)
pnpm --filter @agentproto/catalog-sync generate --refresh  # re-fetch pinned sources

addedAt convention

Some generators (currently llm:openrouter and llm:requesty — the two producing LLMPricing entries) stamp an addedAt?: string field (ISO YYYY-MM-DD) on each catalog entry: the date that model id was first seen by a sync run.

  • Backfill rule. When the provider source itself carries a creation timestamp for the id (OpenRouter's and Requesty's /v1/models both carry a Unix-seconds created field), a brand-new id is backfilled with that date, converted to YYYY-MM-DD. When the source has no such field, the id is stamped with the sync run's own date instead.
  • Never-mutated invariant. Once an id has an addedAt stamp, it is never overwritten by a later run — not even if the source's own created value for that id later resolves to something different. A model id disappearing and later reappearing keeps its ORIGINAL stamp rather than looking newly added.
  • Mechanism: a per-generator ledger file, committed at packages/catalog-sync/ledger/<generator-id>.json (e.g. ledger/llm-openrouter.json) — a flat { "model/id": "YYYY-MM-DD", ... } map, sorted keys, deterministic serialization. Each generator reads its own ledger directly off disk (a plain node:fs read — GeneratorContext intentionally has no general repo-read capability; the ledger is a generator-internal concern, not part of the frozen types.ts contract), merges in the current run's ids via computeAddedAtLedger (see src/added-at.ts), and returns the updated ledger as a second entry in its GeneratedFiles — so runner.ts's existing diff/write logic (and --check's drift detection) covers the ledger file for free, same as any other generated file.
  • Ledger entries are never dropped, even for ids no longer present in a run — the ledger records "first ever seen", not "currently present".

See src/added-at.ts for the implementation and src/generators/llm-openrouter.ts / src/generators/llm-requesty.ts for how a generator wires it in.

CATALOG-CHANGELOG.md

packages/model-catalog/CATALOG-CHANGELOG.md is a human-readable "what models changed" log — NOT the changesets-driven CHANGELOG.md next to it (that one is package-version history, one entry per publish). It answers "what did catalog-sync add or remove, and when" by reading top to bottom.

  • Written automatically by runGenerators (src/runner.ts), not by hand. After collecting every generator's output, the runner diffs each changed *.generated.ts file's top-level id keys (before vs after — see src/changelog.ts's extractRecordIds / diffModelIds) and, when at least one generator actually added or removed a model id, appends one dated section:

    ## 2026-08-31
    
    ### llm:requesty
    - Added: alibaba/qwen3.8-flash, alibaba/qwen3.8-max, ...
    - Removed: anthropic/claude-opus-4-1, ...
    
  • Sections are appended at the END of the file (newest last) — a plain, non-destructive +=. This is a deliberate choice over "newest first"; it means the writer never has to parse and re-emit prior history, only concatenate.

  • A run with no id-level drift emits nothing — no empty section, no touched file, no diff. Pricing-only changes (a model's price moved but no id was added/removed) are NOT logged here; they're visible in the generated file's own git history.

  • addedAt ledger files (ledger/*.json) are deliberately excluded from this diff — they never lose an id (see above), so they carry no "removed" signal, and every "added" id they'd report is already covered by the owning generator's own *.generated.ts diff.

Generators

llm:openrouter

Source: https://openrouter.ai/api/v1/models (pinned snapshot: snapshots/llm-openrouter.json). Emits packages/model-catalog/src/llm/openrouter-routes.generated.ts — a drop-in OPENROUTER_ROUTES: Record<string, LLMPricing> plus the derived OPENROUTER_PROVIDERS list.

  • Per-token USD prices → inputPer1M / outputPer1M (USD per 1M tokens).
  • cache_read / cache_write (when present) → cacheReadMultiplier / cacheWriteMultiplier (ratio vs base input). The committed model-catalog file omits these; this generator emits them when the source carries them (P3 spec: "plus cache fields if the source has them") — additive and LLMPricing-compatible.
  • pricing.overrides entries keyed solely on min_prompt_tokens → a tiers array ({ aboveInputTokens, inputPer1M, outputPer1M, … }) on the row, so long prompts bill at the higher rate. Time-of-day discounts are ignored.
  • Unpriced routes (openrouter/auto) are skipped.
  • addedAt (ISO date, first-seen, never mutated) is stamped per id via the ledger/llm-openrouter.json ledger — see "addedAt convention" above.

llm:requesty

Source: https://router.requesty.ai/v1/models (pinned snapshot: snapshots/llm-requesty.json). Emits packages/model-catalog/src/llm/requesty-routes.generated.ts — a drop-in REQUESTY_ROUTES: Record<string, LLMPricing> plus the derived REQUESTY_PROVIDERS list.

  • Per-token USD prices (JSON numbers) → inputPer1M / outputPer1M.
  • cached_price is emitted as cacheReadMultiplier only when the source also marks supports_caching: true; Requesty has no cache-write price, so cacheWriteMultiplier is never emitted.
  • Live refresh requires REQUESTY_API_KEY to be set; without it the generator reuses the committed snapshot.
  • addedAt (ISO date, first-seen, never mutated) is stamped per id via the ledger/llm-requesty.json ledger — see "addedAt convention" above.

llm:context-windows

Sources: Anthropic, Groq, xAI, and Moonshot models-list endpoints (pinned snapshots: snapshots/llm-anthropic.json, snapshots/llm-groq.json, snapshots/llm-xai.json, snapshots/llm-moonshot.json). Emits packages/model-catalog/src/llm/context-windows.generated.ts — a drop-in CONTEXT_WINDOWS: Record<string, ContextWindowEntry>.

  • contextWindow maps to each provider's max-input/context-length field.
  • maxOutput is captured when the source publishes one.
  • This is not pricing; billing data still comes from llm:openrouter and hand-maintained pricing entries in model-catalog.
  • OpenAI and ZAI/Zhipu are excluded because they don't publish a stable, machine-readable context-window list.

版本与发布记录

@agentproto/catalog-sync 共发布 37 个版本,首次发布于 2026/06/30;过去 12 个月发布了 37 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.9.1latest2026/11/062 天前
0.9.02026/11/044 天前
0.8.122026/11/016 天前
0.8.112026/10/2711 天前
0.8.102026/10/2316 天前
0.8.92026/10/1919 天前

关于 @agentproto/catalog-sync 的常见问题

@agentproto/catalog-sync 是什么?

Build-time generator framework for @agentproto/model-catalog. Generates *.generated.ts from pinned provider sources (LLM, image, video, audio, voice).

如何安装 @agentproto/catalog-sync?

在项目目录运行 npm install @agentproto/catalog-sync,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 catalog-sync,可以用 npx catalog-sync 直接运行。

@agentproto/catalog-sync 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@agentproto/catalog-sync 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@agentproto/catalog-sync 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20.9.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@agentproto/catalog-sync 可以商用吗?

@agentproto/catalog-sync 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@agentproto/catalog-sync 的下载量有多少?

根据 npm 官方下载统计,@agentproto/catalog-sync 在 2026/10/05 – 2026/11/03 这 30 天内被下载 1,795 次,日均约 60 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@agentproto/catalog-sync 还在维护吗?

最新版本 0.9.1 发布于 2026/11/06(2 天前);至今共发布 37 个版本,其中过去 12 个月发布了 37 个;首次发布于 2026/06/30。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。