@agentproto/catalog-sync 0.3.0 → 0.5.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/README.md CHANGED
@@ -66,3 +66,18 @@ Source: `https://openrouter.ai/api/v1/models` (pinned snapshot:
66
66
  (P3 spec: "plus cache fields if the source has them") — additive and
67
67
  `LLMPricing`-compatible.
68
68
  - Unpriced routes (`openrouter/auto`) are skipped.
69
+
70
+ ### `llm:context-windows`
71
+
72
+ Sources: Anthropic, Groq, xAI, and Moonshot models-list endpoints (pinned
73
+ snapshots: `snapshots/llm-anthropic.json`, `snapshots/llm-groq.json`,
74
+ `snapshots/llm-xai.json`, `snapshots/llm-moonshot.json`). Emits
75
+ `packages/model-catalog/src/llm/context-windows.generated.ts` — a drop-in
76
+ `CONTEXT_WINDOWS: Record<string, ContextWindowEntry>`.
77
+
78
+ - `contextWindow` maps to each provider's max-input/context-length field.
79
+ - `maxOutput` is captured when the source publishes one.
80
+ - This is **not pricing**; billing data still comes from `llm:openrouter` and
81
+ hand-maintained pricing entries in `model-catalog`.
82
+ - OpenAI and ZAI/Zhipu are excluded because they don't publish a stable,
83
+ machine-readable context-window list.
package/dist/bin.mjs CHANGED
@@ -133,6 +133,252 @@ var llmOpenRouterGenerator = defineGenerator({
133
133
  sources,
134
134
  generate
135
135
  });
136
+ var REQUESTY_MODELS_URL = "https://router.requesty.ai/v1/models";
137
+ var OUTPUT_PATH2 = "packages/model-catalog/src/llm/requesty-routes.generated.ts";
138
+ var ModelSchema2 = z.object({
139
+ id: z.string(),
140
+ input_price: z.number().optional(),
141
+ output_price: z.number().optional(),
142
+ cached_price: z.number().optional(),
143
+ supports_caching: z.boolean().optional()
144
+ }).passthrough();
145
+ var SnapshotSchema2 = z.object({
146
+ data: z.array(ModelSchema2)
147
+ });
148
+ function round62(n) {
149
+ return Math.round(n * 1e6) / 1e6;
150
+ }
151
+ function per1m2(tokenPrice) {
152
+ if (tokenPrice === void 0) return void 0;
153
+ if (!Number.isFinite(tokenPrice)) return void 0;
154
+ return round62(tokenPrice * 1e6);
155
+ }
156
+ function fmt2(n) {
157
+ if (!Number.isFinite(n)) return "0";
158
+ return `${round62(n)}`;
159
+ }
160
+ function vendorOf2(id) {
161
+ if (!id.includes("/")) return id;
162
+ return id.split("/")[0] ?? id;
163
+ }
164
+ function serializeEntry2(e) {
165
+ const fields = [
166
+ `inputPer1M: ${fmt2(e.inputPer1M)}`,
167
+ `outputPer1M: ${fmt2(e.outputPer1M)}`
168
+ ];
169
+ if (e.cacheReadMultiplier !== void 0) {
170
+ fields.push(`cacheReadMultiplier: ${fmt2(e.cacheReadMultiplier)}`);
171
+ }
172
+ fields.push(`vendor: ${JSON.stringify(e.vendor)}`);
173
+ fields.push(`provider: ${JSON.stringify(e.provider)}`);
174
+ return `{
175
+ ${fields.join(",\n ")},
176
+ }`;
177
+ }
178
+ function serializeFile2(entries) {
179
+ const ids = Object.keys(entries).sort();
180
+ const providers = Array.from(new Set(ids.map(vendorOf2))).sort();
181
+ const lines = [
182
+ "// AUTO-GENERATED by @agentproto/catalog-sync (llm:requesty).",
183
+ "// Do not edit by hand \u2014 re-run `pnpm --filter @agentproto/catalog-sync generate`.",
184
+ `// Source: ${REQUESTY_MODELS_URL}`,
185
+ "// Pricing carries provider USD (inputPer1M / outputPer1M) plus a cache",
186
+ "// multiplier (cacheReadMultiplier) derived from the source's cached_price",
187
+ "// per-token field when `supports_caching` is true. Requesty has no",
188
+ "// cache-write price, so cacheWriteMultiplier is never emitted.",
189
+ "",
190
+ 'import type { LLMPricing } from "./catalog.js"',
191
+ "",
192
+ "export const REQUESTY_ROUTES: Record<string, LLMPricing> = {"
193
+ ];
194
+ for (const id of ids) {
195
+ lines.push(` ${JSON.stringify(id)}: ${serializeEntry2(entries[id])},`);
196
+ }
197
+ lines.push("}");
198
+ lines.push("");
199
+ lines.push("/** Provider slugs treated as Requesty routes by the picker. */");
200
+ lines.push("export const REQUESTY_PROVIDERS: readonly string[] = [");
201
+ for (const p of providers) {
202
+ lines.push(` ${JSON.stringify(p)},`);
203
+ }
204
+ lines.push("]");
205
+ lines.push("");
206
+ return lines.join("\n");
207
+ }
208
+ async function generate2(ctx) {
209
+ const src = sources2[0];
210
+ if (!src) throw new Error("llm:requesty: no source configured");
211
+ const parsed = SnapshotSchema2.parse(await ctx.fetchSource(src));
212
+ const entries = {};
213
+ for (const model of parsed.data) {
214
+ const inputPer1M = per1m2(model.input_price);
215
+ const outputPer1M = per1m2(model.output_price);
216
+ if (inputPer1M === void 0 || outputPer1M === void 0) continue;
217
+ if (inputPer1M === 0 && outputPer1M === 0) continue;
218
+ const entry = {
219
+ inputPer1M,
220
+ outputPer1M,
221
+ vendor: vendorOf2(model.id),
222
+ provider: "requesty"
223
+ };
224
+ if (model.supports_caching === true && inputPer1M > 0) {
225
+ const cachePer1M = per1m2(model.cached_price);
226
+ if (cachePer1M !== void 0) {
227
+ entry.cacheReadMultiplier = round62(cachePer1M / inputPer1M);
228
+ }
229
+ }
230
+ entries[model.id] = entry;
231
+ }
232
+ return { [OUTPUT_PATH2]: serializeFile2(entries) };
233
+ }
234
+ var sources2 = [
235
+ {
236
+ id: "llm-requesty",
237
+ url: REQUESTY_MODELS_URL,
238
+ // Live refresh needs the account key (Bearer). Without REQUESTY_API_KEY
239
+ // set, the framework reuses the committed snapshot.
240
+ headers: { Authorization: "Bearer env:REQUESTY_API_KEY" }
241
+ }
242
+ ];
243
+ var llmRequestyGenerator = defineGenerator({
244
+ name: "llm:requesty",
245
+ modality: "llm",
246
+ sources: sources2,
247
+ generate: generate2
248
+ });
249
+ var OUTPUT_PATH3 = "packages/model-catalog/src/llm/context-windows.generated.ts";
250
+ var AnthropicModelSchema = z.object({
251
+ id: z.string(),
252
+ display_name: z.string().optional(),
253
+ max_input_tokens: z.number().optional(),
254
+ max_tokens: z.number().optional()
255
+ }).passthrough();
256
+ var AnthropicSnapshotSchema = z.object({ data: z.array(AnthropicModelSchema) });
257
+ var GroqModelSchema = z.object({
258
+ id: z.string(),
259
+ context_window: z.number().optional(),
260
+ max_completion_tokens: z.number().optional()
261
+ }).passthrough();
262
+ var GroqSnapshotSchema = z.object({ data: z.array(GroqModelSchema) });
263
+ var XaiModelSchema = z.object({
264
+ id: z.string(),
265
+ context_length: z.number().nullable().optional()
266
+ }).passthrough();
267
+ var XaiSnapshotSchema = z.object({ data: z.array(XaiModelSchema) });
268
+ var MoonshotModelSchema = z.object({
269
+ id: z.string(),
270
+ context_length: z.number().optional()
271
+ }).passthrough();
272
+ var MoonshotSnapshotSchema = z.object({ data: z.array(MoonshotModelSchema) });
273
+ function serializeEntry3(e) {
274
+ const fields = [`contextWindow: ${e.contextWindow}`];
275
+ if (e.maxOutput !== void 0) fields.push(`maxOutput: ${e.maxOutput}`);
276
+ if (e.displayName !== void 0) fields.push(`displayName: ${JSON.stringify(e.displayName)}`);
277
+ fields.push(`provider: ${JSON.stringify(e.provider)}`);
278
+ return `{ ${fields.join(", ")} }`;
279
+ }
280
+ function serializeFile3(entries) {
281
+ const ids = Object.keys(entries).sort();
282
+ const lines = [
283
+ "// AUTO-GENERATED by @agentproto/catalog-sync (llm:context-windows).",
284
+ "// Do not edit by hand \u2014 re-run `pnpm --filter @agentproto/catalog-sync generate --refresh`.",
285
+ "// Sources: api.anthropic.com/v1/models, api.groq.com/openai/v1/models,",
286
+ "// api.x.ai/v1/models, api.moonshot.ai/v1/models",
287
+ "// Context window (max input tokens) + max output tokens per live model id.",
288
+ "// NOT pricing \u2014 see LLM_PRICING_CATALOG / OPENROUTER_ROUTES in catalog.ts.",
289
+ "",
290
+ "export interface ContextWindowEntry {",
291
+ " contextWindow: number",
292
+ " maxOutput?: number",
293
+ " displayName?: string",
294
+ ' provider: "anthropic" | "groq" | "xai" | "moonshot"',
295
+ "}",
296
+ "",
297
+ "export const CONTEXT_WINDOWS: Record<string, ContextWindowEntry> = {"
298
+ ];
299
+ for (const id of ids) {
300
+ lines.push(` ${JSON.stringify(id)}: ${serializeEntry3(entries[id])},`);
301
+ }
302
+ lines.push("}");
303
+ lines.push("");
304
+ return lines.join("\n");
305
+ }
306
+ async function generate3(ctx) {
307
+ const entries = {};
308
+ const anthropicSrc = sources3.find((s) => s.id === "llm-anthropic");
309
+ if (anthropicSrc) {
310
+ const parsed = AnthropicSnapshotSchema.parse(await ctx.fetchSource(anthropicSrc));
311
+ for (const m of parsed.data) {
312
+ if (!m.max_input_tokens || !m.max_tokens) continue;
313
+ entries[m.id] = {
314
+ contextWindow: m.max_input_tokens,
315
+ maxOutput: m.max_tokens,
316
+ ...m.display_name ? { displayName: m.display_name } : {},
317
+ provider: "anthropic"
318
+ };
319
+ }
320
+ }
321
+ const groqSrc = sources3.find((s) => s.id === "llm-groq");
322
+ if (groqSrc) {
323
+ const parsed = GroqSnapshotSchema.parse(await ctx.fetchSource(groqSrc));
324
+ for (const m of parsed.data) {
325
+ if (!m.context_window) continue;
326
+ entries[m.id] = {
327
+ contextWindow: m.context_window,
328
+ ...m.max_completion_tokens ? { maxOutput: m.max_completion_tokens } : {},
329
+ provider: "groq"
330
+ };
331
+ }
332
+ }
333
+ const xaiSrc = sources3.find((s) => s.id === "llm-xai");
334
+ if (xaiSrc) {
335
+ const parsed = XaiSnapshotSchema.parse(await ctx.fetchSource(xaiSrc));
336
+ for (const m of parsed.data) {
337
+ if (!m.context_length) continue;
338
+ entries[m.id] = { contextWindow: m.context_length, provider: "xai" };
339
+ }
340
+ }
341
+ const moonshotSrc = sources3.find((s) => s.id === "llm-moonshot");
342
+ if (moonshotSrc) {
343
+ const parsed = MoonshotSnapshotSchema.parse(await ctx.fetchSource(moonshotSrc));
344
+ for (const m of parsed.data) {
345
+ if (!m.context_length) continue;
346
+ entries[m.id] = { contextWindow: m.context_length, provider: "moonshot" };
347
+ }
348
+ }
349
+ return { [OUTPUT_PATH3]: serializeFile3(entries) };
350
+ }
351
+ var sources3 = [
352
+ {
353
+ id: "llm-anthropic",
354
+ url: "https://api.anthropic.com/v1/models?limit=1000",
355
+ headers: {
356
+ "x-api-key": "env:ANTHROPIC_API_KEY",
357
+ "anthropic-version": "2023-06-01"
358
+ }
359
+ },
360
+ {
361
+ id: "llm-groq",
362
+ url: "https://api.groq.com/openai/v1/models",
363
+ headers: { Authorization: "Bearer env:GROQ_API_KEY" }
364
+ },
365
+ {
366
+ id: "llm-xai",
367
+ url: "https://api.x.ai/v1/models",
368
+ headers: { Authorization: "Bearer env:XAI_API_KEY" }
369
+ },
370
+ {
371
+ id: "llm-moonshot",
372
+ url: "https://api.moonshot.ai/v1/models",
373
+ headers: { Authorization: "Bearer env:MOONSHOT_API_KEY" }
374
+ }
375
+ ];
376
+ var llmContextWindowsGenerator = defineGenerator({
377
+ name: "llm:context-windows",
378
+ modality: "llm",
379
+ sources: sources3,
380
+ generate: generate3
381
+ });
136
382
 
137
383
  // src/generators/serialize-voices.ts
138
384
  function serializeVoice(v) {
@@ -176,7 +422,7 @@ var ELEVENLABS_SOURCE = {
176
422
  // Live refresh needs the account key; offline reads ignore this.
177
423
  headers: { "xi-api-key": "env:ELEVENLABS_API_KEY" }
178
424
  };
179
- var OUTPUT_PATH2 = "packages/catalog-sync/generated/voice-elevenlabs.generated.ts";
425
+ var OUTPUT_PATH4 = "packages/catalog-sync/generated/voice-elevenlabs.generated.ts";
180
426
  var voiceElevenlabs = defineGenerator({
181
427
  name: "voice:elevenlabs",
182
428
  modality: "voice",
@@ -187,7 +433,7 @@ var voiceElevenlabs = defineGenerator({
187
433
  );
188
434
  const voices = mapElevenLabsVoices(snapshot);
189
435
  return {
190
- [OUTPUT_PATH2]: serializeVoiceModule(
436
+ [OUTPUT_PATH4]: serializeVoiceModule(
191
437
  "voice:elevenlabs",
192
438
  "ELEVENLABS_VOICES",
193
439
  voices
@@ -207,7 +453,7 @@ var MINIMAX_SOURCE = {
207
453
  },
208
454
  body: { voice_type: "system" }
209
455
  };
210
- var OUTPUT_PATH3 = "packages/catalog-sync/generated/voice-minimax.generated.ts";
456
+ var OUTPUT_PATH5 = "packages/catalog-sync/generated/voice-minimax.generated.ts";
211
457
  var voiceMinimax = defineGenerator({
212
458
  name: "voice:minimax",
213
459
  modality: "voice",
@@ -218,7 +464,7 @@ var voiceMinimax = defineGenerator({
218
464
  );
219
465
  const voices = mapMinimaxVoices(snapshot);
220
466
  return {
221
- [OUTPUT_PATH3]: serializeVoiceModule(
467
+ [OUTPUT_PATH5]: serializeVoiceModule(
222
468
  "voice:minimax",
223
469
  "MINIMAX_VOICES",
224
470
  voices
@@ -631,6 +877,8 @@ var refresh = flags.has("--refresh");
631
877
  var check = flags.has("--check");
632
878
  var generators = [
633
879
  llmOpenRouterGenerator,
880
+ llmRequestyGenerator,
881
+ llmContextWindowsGenerator,
634
882
  voiceElevenlabs,
635
883
  voiceMinimax,
636
884
  imageReplicate