Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ Model catalog data as JSON files, refreshed on a schedule.
https://raw.githubusercontent.com/cloudstack-llc/model-catalog/main/v1/prices.json
https://raw.githubusercontent.com/cloudstack-llc/model-catalog/main/v1/ollama-models.json
https://raw.githubusercontent.com/cloudstack-llc/model-catalog/main/v1/featured-models.json
https://raw.githubusercontent.com/cloudstack-llc/model-catalog/main/v1/smart-route-starters.json
```

| File | Contents | Source | Cadence |
| --- | --- | --- | --- |
| `v1/prices.json` | Token pricing for hosted models | [models.dev](https://models.dev) | 6 hours |
| `v1/ollama-models.json` | The Ollama library: models, tags, sizes, context windows | [ollama.com](https://ollama.com/library) | 12 hours |
| `v1/featured-models.json` | Curated local models worth downloading, grouped into collections | Curated; resolved against Ollama and Hugging Face | On change |
| `v1/smart-route-starters.json` | Model-neutral Smart Route starters, grouped by use | Curated | On change |

# Token pricing

Expand Down Expand Up @@ -65,6 +67,27 @@ node scripts/generate.mjs # fetch upstream and rewrite v1/prices.json

No dependencies.

# Smart Route starters

`v1/smart-route-starters.json` gives Msty Nexus a model-neutral starting point
for common routing jobs. A starter contains the route name, classifier lanes,
target guidance, and the endpoint families it expects. It never contains a
model or pool ID. Nexus asks the person adding it to choose those targets.

Collections reference starters by ID, so one starter can appear in more than
one part of the catalog without being copied. `revision` changes when the
curated starter changes. Existing Smart Routes are independent copies and are
never changed by a catalog update.

All displayed descriptions use first-person copy. Lane descriptions are capped
at 512 bytes because that is the classifier input limit.

Validate a catalog edit before committing it:

```bash
node scripts/smart-route-starters-verify.mjs
```

Optional `REFRESH_TOKEN` secret: a fine-grained PAT with `contents: write` on this
repository. GitHub disables scheduled workflows after 60 days without repository activity,
and pushes made with the default `GITHUB_TOKEN` do not reset that clock.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"license": "MIT",
"scripts": {
"test": "node --test scripts/*.test.mjs",
"verify": "node scripts/verify.mjs && node scripts/ollama-verify.mjs",
"verify": "node scripts/verify.mjs && node scripts/ollama-verify.mjs && node scripts/smart-route-starters-verify.mjs",
"generate": "node scripts/generate.mjs",
"generate:ollama": "node scripts/ollama-generate.mjs"
}
Expand Down
30 changes: 30 additions & 0 deletions scripts/smart-route-starters-verify.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Validates the curated Smart Route starter artifact without using the network.
//
// Run: node scripts/smart-route-starters-verify.mjs [path]

import { readFile } from "node:fs/promises";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";

import { validateSmartRouteStarters } from "./smart-route-starters.mjs";

const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const path = resolve(repoRoot, process.argv[2] ?? "v1/smart-route-starters.json");
const text = await readFile(path, "utf8");
const artifact = JSON.parse(text);
const problems = validateSmartRouteStarters(artifact);

if (`${JSON.stringify(artifact, null, 2)}\n` !== text) {
problems.push("file must use the canonical two-space JSON format");
}

if (problems.length > 0) {
for (const problem of problems) console.error(`invalid artifact: ${problem}`);
process.exit(1);
}

const lanes = artifact.starters.reduce((total, starter) => total + starter.lanes.length, 0);
console.log(
`ok: ${artifact.starters.length} Smart Route starters, ${artifact.collections.length} collections, ${lanes} lanes`,
);

256 changes: 256 additions & 0 deletions scripts/smart-route-starters.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
const ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
const ENDPOINT_FAMILIES = new Set([
"anthropic.messages",
"openai.chat_completions",
"openai.images",
"openai.responses",
]);
const BANNED_WORDS = new Set([
"delve",
"empower",
"facilitate",
"foster",
"harness",
"leverage",
"robust",
"streamline",
"supercharge",
"transformative",
"utilize",
]);

function byteLength(value) {
return Buffer.byteLength(value, "utf8");
}

function cleanText(problems, value, label, maxBytes, firstPerson = false) {
if (typeof value !== "string" || value.trim() !== value || value === "") {
problems.push(`${label} must be a non-empty trimmed string`);
return "";
}
if (byteLength(value) > maxBytes) {
problems.push(`${label} is longer than ${maxBytes} bytes`);
}
if (/\p{Cc}/u.test(value) || /[<>]/.test(value)) {
problems.push(`${label} contains control characters or markup`);
}
if (value.includes("—")) {
problems.push(`${label} uses an em dash`);
}
if (firstPerson && !/^I(?:\b|['’])/.test(value)) {
problems.push(`${label} must use first-person copy`);
}
const words = value.toLowerCase().match(/[a-z]+/g) ?? [];
for (const word of words) {
if (BANNED_WORDS.has(word)) {
problems.push(`${label} uses banned word ${word}`);
}
}
return value;
}

function exactKeys(problems, value, label, allowed) {
if (value === null || typeof value !== "object" || Array.isArray(value)) {
problems.push(`${label} must be an object`);
return false;
}
for (const key of Object.keys(value)) {
if (!allowed.has(key)) {
problems.push(`${label} has unsupported field ${key}`);
}
}
return true;
}

function validID(problems, value, label) {
if (typeof value !== "string" || !ID.test(value) || value.length > 64) {
problems.push(`${label} must be a lowercase kebab-case id up to 64 characters`);
return "";
}
return value;
}

function findForbiddenTargetFields(value, path, problems) {
if (Array.isArray(value)) {
value.forEach((entry, index) =>
findForbiddenTargetFields(entry, `${path}[${index}]`, problems),
);
return;
}
if (value === null || typeof value !== "object") return;
for (const [key, entry] of Object.entries(value)) {
if (/model.?id/i.test(key) || /target.?id/i.test(key)) {
problems.push(`${path}.${key} must not bind a starter to a model`);
}
findForbiddenTargetFields(entry, `${path}.${key}`, problems);
}
}

export function validateSmartRouteStarters(artifact) {
const problems = [];
if (!exactKeys(
problems,
artifact,
"artifact",
new Set(["schema_version", "generated_at", "locale", "collections", "starters"]),
)) return problems;

if (artifact.schema_version !== 1) {
problems.push("schema_version must be 1");
}
if (
typeof artifact.generated_at !== "string" ||
Number.isNaN(Date.parse(artifact.generated_at))
) {
problems.push("generated_at must be an RFC 3339 timestamp");
}
if (artifact.locale !== "en") {
problems.push("locale must be en for the v1 artifact");
}
if (!Array.isArray(artifact.starters) || artifact.starters.length === 0) {
problems.push("starters must contain at least one starter");
}
if ((artifact.starters?.length ?? 0) > 100) {
problems.push("starters must contain at most 100 starters");
}

const starterIDs = new Set();
for (const [starterIndex, starter] of (artifact.starters ?? []).entries()) {
const label = `starters[${starterIndex}]`;
if (!exactKeys(
problems,
starter,
label,
new Set([
"id",
"revision",
"name",
"summary",
"notice",
"tags",
"endpoint_families",
"lanes",
"fallback",
]),
)) continue;

const id = validID(problems, starter.id, `${label}.id`);
if (starterIDs.has(id)) problems.push(`${label}.id duplicates ${id}`);
if (id !== "") starterIDs.add(id);
if (!Number.isInteger(starter.revision) || starter.revision < 1) {
problems.push(`${label}.revision must be a positive integer`);
}
cleanText(problems, starter.name, `${label}.name`, 128);
cleanText(problems, starter.summary, `${label}.summary`, 256, true);
if (starter.notice !== undefined) {
cleanText(problems, starter.notice, `${label}.notice`, 256, true);
}

if (!Array.isArray(starter.tags) || starter.tags.length === 0 || starter.tags.length > 12) {
problems.push(`${label}.tags must contain 1 to 12 tags`);
} else {
const tags = new Set();
for (const [tagIndex, tag] of starter.tags.entries()) {
const parsed = validID(problems, tag, `${label}.tags[${tagIndex}]`);
if (tags.has(parsed)) problems.push(`${label}.tags duplicates ${parsed}`);
tags.add(parsed);
}
}

if (
!Array.isArray(starter.endpoint_families) ||
starter.endpoint_families.length === 0 ||
starter.endpoint_families.length > ENDPOINT_FAMILIES.size
) {
problems.push(`${label}.endpoint_families must contain supported generation endpoints`);
} else {
const families = new Set();
for (const family of starter.endpoint_families) {
if (!ENDPOINT_FAMILIES.has(family)) {
problems.push(`${label}.endpoint_families contains unsupported endpoint ${family}`);
}
if (families.has(family)) {
problems.push(`${label}.endpoint_families duplicates ${family}`);
}
families.add(family);
}
}

if (!Array.isArray(starter.lanes) || starter.lanes.length < 2 || starter.lanes.length > 12) {
problems.push(`${label}.lanes must contain 2 to 12 lanes`);
} else {
const laneIDs = new Set();
for (const [laneIndex, lane] of starter.lanes.entries()) {
const laneLabel = `${label}.lanes[${laneIndex}]`;
if (!exactKeys(
problems,
lane,
laneLabel,
new Set(["id", "name", "description", "target_hint"]),
)) continue;
const laneID = validID(problems, lane.id, `${laneLabel}.id`);
if (laneIDs.has(laneID)) problems.push(`${laneLabel}.id duplicates ${laneID}`);
laneIDs.add(laneID);
cleanText(problems, lane.name, `${laneLabel}.name`, 128);
cleanText(problems, lane.description, `${laneLabel}.description`, 512, true);
cleanText(problems, lane.target_hint, `${laneLabel}.target_hint`, 256, true);
}
}

if (exactKeys(problems, starter.fallback, `${label}.fallback`, new Set(["target_hint"]))) {
cleanText(
problems,
starter.fallback.target_hint,
`${label}.fallback.target_hint`,
256,
true,
);
}
}

if (!Array.isArray(artifact.collections) || artifact.collections.length === 0) {
problems.push("collections must contain at least one collection");
}
if ((artifact.collections?.length ?? 0) > 20) {
problems.push("collections must contain at most 20 collections");
}
const collectionIDs = new Set();
const referenced = new Set();
for (const [collectionIndex, collection] of (artifact.collections ?? []).entries()) {
const label = `collections[${collectionIndex}]`;
if (!exactKeys(
problems,
collection,
label,
new Set(["id", "title", "description", "starters"]),
)) continue;
const id = validID(problems, collection.id, `${label}.id`);
if (collectionIDs.has(id)) problems.push(`${label}.id duplicates ${id}`);
collectionIDs.add(id);
cleanText(problems, collection.title, `${label}.title`, 128);
cleanText(problems, collection.description, `${label}.description`, 256, true);
if (!Array.isArray(collection.starters) || collection.starters.length === 0) {
problems.push(`${label}.starters must contain at least one starter id`);
continue;
}
const localReferences = new Set();
for (const [referenceIndex, reference] of collection.starters.entries()) {
validID(problems, reference, `${label}.starters[${referenceIndex}]`);
if (!starterIDs.has(reference)) {
problems.push(`${label}.starters references missing starter ${reference}`);
}
if (localReferences.has(reference)) {
problems.push(`${label}.starters duplicates ${reference}`);
}
localReferences.add(reference);
referenced.add(reference);
}
}
for (const id of starterIDs) {
if (!referenced.has(id)) problems.push(`starter ${id} is not in a collection`);
}

findForbiddenTargetFields(artifact, "artifact", problems);
return problems;
}

Loading