mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-13 18:52:18 +03:00
* docs(reference): regenerate PROVIDER_REFERENCE from live provider modules The catalog was hand-stale at 291 since 2026-08-05 while the live provider modules define 338 unique IDs. The generator also omitted the NOAUTH_PROVIDERS module entirely (10 providers) and hardcoded the executor count in its footer; both are now sourced from the live modules. Refs #9985 * docs: refresh stale counts across README/AGENTS/llm.txt and architecture docs Every count updated to values measured from the live code on 2026-08-12: providers 291/271/248/236/226/212->338, migrations 110/117/130->144, MCP tools 94/99/104->105 (base 42->43), scopes 13/32->31, strategies 17/18->19, Auto-Combo factors 12/13->14 (sessionAvailability row added to the table), executors 67/78/84/89->101, quality gates ~48->~80, locales 29/30/39/40+->43 (41 non-source), A2A skills 5->6 (list-capabilities), free tier 43 pools/516 models/~1.53B/~2.15B->42/495/~1.51B/~2.13B, contributors 500+->320+ (324 unique emails), llm.txt version 3.8.47->3.8.50. llm.txt i18n mirrors resynced (headers preserved, body mirrored). Refs #9985 * docs(diagrams): sync SVG hero/pillars/comparison/cli/tier numbers Text nodes and aria-labels only; layout, coordinates and animation values untouched. providers 278/290->338 (cli list footer 264->334 more), MCP tools 104->105, strategies 18->19, free tier 43 pools/460+/516 models->42/495, headline ~1.53B/~2.15B->~1.51B/~2.13B. All six SVGs re-validated as XML. Refs #9985 * feat(check): harden docs-counts gate - live provider source, llm.txt, migrations, SVGs The gate trusted PROVIDER_REFERENCE.md as the provider total, so a hand-stale doc (291 vs 338 live) kept it falsely green. New STRICT checks: doc total vs the live provider modules (same collections the generator unions), provider count in llm.txt and package.json description, migration count vs README/AGENTS/llm.txt, and a canonical-number sweep (providers/MCP tools/strategies/pools) over the six README SVG diagrams with coordinate/attribute-safe patterns. TDD: 9 new unit tests (red first on the missing exports, green after) in tests/unit/check-docs-counts-sync.test.ts. Refs #9985 * docs(readme): refresh What's New range and add v3.8.50 cycle highlights --------- Co-authored-by: backryun <bakryun0718@proton.me>
244 lines
9.3 KiB
JavaScript
244 lines
9.3 KiB
JavaScript
#!/usr/bin/env node
|
|
// Generates docs/reference/PROVIDER_REFERENCE.md from src/shared/constants/providers.ts.
|
|
// Run: node --import tsx scripts/docs/gen-provider-reference.ts
|
|
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import {
|
|
FREE_PROVIDERS,
|
|
NOAUTH_PROVIDERS,
|
|
OAUTH_PROVIDERS,
|
|
WEB_COOKIE_PROVIDERS,
|
|
APIKEY_PROVIDERS,
|
|
LOCAL_PROVIDERS,
|
|
SEARCH_PROVIDERS,
|
|
AUDIO_ONLY_PROVIDERS,
|
|
UPSTREAM_PROXY_PROVIDERS,
|
|
CLOUD_AGENT_PROVIDERS,
|
|
SYSTEM_PROVIDERS,
|
|
IMAGE_ONLY_PROVIDER_IDS,
|
|
AGGREGATOR_PROVIDER_IDS,
|
|
ENTERPRISE_CLOUD_PROVIDER_IDS,
|
|
VIDEO_PROVIDER_IDS,
|
|
EMBEDDING_RERANK_PROVIDER_IDS,
|
|
SELF_HOSTED_CHAT_PROVIDER_IDS,
|
|
} from "../../src/shared/constants/providers.ts";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const ROOT = path.resolve(__dirname, "..", "..");
|
|
const OUT_FILE = path.join(ROOT, "docs", "reference", "PROVIDER_REFERENCE.md");
|
|
|
|
type ProviderRecord = {
|
|
id: string;
|
|
alias?: string | undefined;
|
|
name: string;
|
|
icon?: string;
|
|
color?: string;
|
|
textIcon?: string;
|
|
website?: string;
|
|
authHint?: string;
|
|
freeNote?: string;
|
|
hasFree?: boolean;
|
|
deprecated?: boolean;
|
|
deprecationReason?: string;
|
|
/**
|
|
* #7286: native function calling / prompt-emulated via webTools.ts / silently dropped.
|
|
* Loosely typed `string` (not a literal union) — the source provider-catalog object
|
|
* literals infer widened `string` for this field and are passed in as-is.
|
|
*/
|
|
toolCalling?: string;
|
|
[k: string]: unknown;
|
|
};
|
|
|
|
function asRecords(map: Record<string, ProviderRecord>): ProviderRecord[] {
|
|
return Object.values(map).map((p) => ({ ...p }));
|
|
}
|
|
|
|
function escapeCell(value: string | undefined): string {
|
|
if (!value) return "—";
|
|
// Escape backslash first so the subsequent escapes don't double-escape it.
|
|
return value.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
}
|
|
|
|
function row(p: ProviderRecord, category: string, includeToolCalling: boolean): string {
|
|
const alias = p.alias ? `\`${p.alias}\`` : "—";
|
|
const hint = p.deprecated
|
|
? `⚠️ **DEPRECATED.** ${escapeCell(p.deprecationReason)}`
|
|
: escapeCell(p.authHint || p.freeNote);
|
|
const link = p.website ? `[link](${p.website})` : "—";
|
|
const base = `| \`${p.id}\` | ${alias} | ${escapeCell(p.name)} | ${category} | ${link} | ${hint} |`;
|
|
return includeToolCalling ? `${base} ${escapeCell(p.toolCalling)} |` : base;
|
|
}
|
|
|
|
/** #7286: only render the "Tool calling" column when at least one record in the section sets it. */
|
|
function hasToolCallingColumn(rows: ProviderRecord[]): boolean {
|
|
return rows.some((p) => typeof p.toolCalling === "string");
|
|
}
|
|
|
|
function categoryTags(id: string): string[] {
|
|
const tags: string[] = [];
|
|
if (IMAGE_ONLY_PROVIDER_IDS.has(id)) tags.push("image");
|
|
if (VIDEO_PROVIDER_IDS.has(id)) tags.push("video");
|
|
if (AGGREGATOR_PROVIDER_IDS.has(id)) tags.push("aggregator");
|
|
if (ENTERPRISE_CLOUD_PROVIDER_IDS.has(id)) tags.push("enterprise");
|
|
if (EMBEDDING_RERANK_PROVIDER_IDS.has(id)) tags.push("embed/rerank");
|
|
if (SELF_HOSTED_CHAT_PROVIDER_IDS.has(id)) tags.push("self-hosted");
|
|
return tags;
|
|
}
|
|
|
|
function sortById(rows: ProviderRecord[]): ProviderRecord[] {
|
|
return [...rows].sort((a, b) => a.id.localeCompare(b.id));
|
|
}
|
|
|
|
function buildSection(title: string, rows: ProviderRecord[], category: string): string {
|
|
if (rows.length === 0) return "";
|
|
const lines: string[] = [];
|
|
lines.push(`## ${title} (${rows.length})\n`);
|
|
const includeToolCalling = hasToolCallingColumn(rows);
|
|
lines.push(
|
|
includeToolCalling
|
|
? "| ID | Alias | Name | Tags | Website | Notes | Tool calling |"
|
|
: "| ID | Alias | Name | Tags | Website | Notes |"
|
|
);
|
|
lines.push(
|
|
includeToolCalling
|
|
? "|----|-------|------|------|---------|-------|--------------|"
|
|
: "|----|-------|------|------|---------|-------|"
|
|
);
|
|
for (const p of sortById(rows)) {
|
|
const tags = [category, ...categoryTags(p.id)].join(", ");
|
|
lines.push(row(p, tags, includeToolCalling));
|
|
}
|
|
lines.push("");
|
|
return lines.join("\n");
|
|
}
|
|
|
|
function buildHeader(total: number): string {
|
|
const date = new Date().toISOString().slice(0, 10);
|
|
const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, "package.json"), "utf8")) as {
|
|
version?: string;
|
|
};
|
|
return [
|
|
"---",
|
|
'title: "Provider Reference"',
|
|
`version: ${pkg.version || "unknown"}`,
|
|
`lastUpdated: ${date}`,
|
|
"---",
|
|
"",
|
|
"# Provider Reference",
|
|
"",
|
|
`> **Auto-generated** from \`src/shared/constants/providers.ts\` — do not edit by hand.`,
|
|
`> Regenerate with: \`npm run gen:provider-reference\``,
|
|
`> **Last generated:** ${date}`,
|
|
"",
|
|
`Total providers: **${total}**. See category breakdown below.`,
|
|
"",
|
|
"## Categories",
|
|
"",
|
|
"- **Free** — free tier with API key (configured via dashboard)",
|
|
"- **No-auth** — public endpoints that require no key or sign-in at all",
|
|
"- **OAuth** — sign-in flow handled by OmniRoute, no API key needed",
|
|
"- **Web cookie** — wraps the provider's web app via cookie auth",
|
|
"- **API key** — paid provider configured via API key (free credits may apply)",
|
|
"- **Local** — runs on the user's machine (Ollama, LM Studio, vLLM, etc.)",
|
|
"- **Search** — web search providers",
|
|
"- **Audio** — audio-only providers (TTS/STT)",
|
|
"- **Upstream proxy** — providers that proxy to other providers",
|
|
"- **Cloud agent** — long-running coding agents (Codex Cloud, Devin, Jules)",
|
|
"- **System** — OmniRoute-internal providers (loopback, etc.)",
|
|
"",
|
|
"Additional tags: `image`, `video`, `aggregator`, `enterprise`, `embed/rerank`, `self-hosted`.",
|
|
"",
|
|
"`Tool calling` (where shown): `native` — real function-calling API; `emulated` — the " +
|
|
"`tools` array is prompt-emulated via `webTools.ts` (regex-parsed `<tool>{...}</tool>` " +
|
|
"blocks); `none` — `tools` is currently silently dropped. See #7286.",
|
|
"",
|
|
"Use the dashboard at `/dashboard/providers` to enable, configure, and test each provider.",
|
|
"",
|
|
"---",
|
|
"",
|
|
].join("\n");
|
|
}
|
|
|
|
function countExecutorImpls(): number {
|
|
const dir = path.join(ROOT, "open-sse", "executors");
|
|
const nonImpl = new Set(["index.ts", "index.mts", "types.ts", "base.ts", "constants.ts"]);
|
|
return fs
|
|
.readdirSync(dir)
|
|
.filter(
|
|
(f) => f.endsWith(".ts") && !f.endsWith(".test.ts") && !f.startsWith("__") && !nonImpl.has(f)
|
|
).length;
|
|
}
|
|
|
|
function main() {
|
|
const free = asRecords(FREE_PROVIDERS);
|
|
const noauth = asRecords(NOAUTH_PROVIDERS as Record<string, ProviderRecord>);
|
|
const oauth = asRecords(OAUTH_PROVIDERS);
|
|
const webCookie = asRecords(WEB_COOKIE_PROVIDERS);
|
|
const apiKey = asRecords(APIKEY_PROVIDERS);
|
|
const local = asRecords(LOCAL_PROVIDERS);
|
|
const search = asRecords(SEARCH_PROVIDERS);
|
|
const audio = asRecords(AUDIO_ONLY_PROVIDERS);
|
|
const upstreamProxy = asRecords(UPSTREAM_PROXY_PROVIDERS);
|
|
const cloudAgent = asRecords(CLOUD_AGENT_PROVIDERS);
|
|
const system = asRecords(SYSTEM_PROVIDERS);
|
|
|
|
const allIds = new Set<string>([
|
|
...free.map((p) => p.id),
|
|
...noauth.map((p) => p.id),
|
|
...oauth.map((p) => p.id),
|
|
...webCookie.map((p) => p.id),
|
|
...apiKey.map((p) => p.id),
|
|
...local.map((p) => p.id),
|
|
...search.map((p) => p.id),
|
|
...audio.map((p) => p.id),
|
|
...upstreamProxy.map((p) => p.id),
|
|
...cloudAgent.map((p) => p.id),
|
|
...system.map((p) => p.id),
|
|
]);
|
|
|
|
const sections = [
|
|
buildSection("Free Tier (OAuth-first or no-key)", free, "Free"),
|
|
buildSection("No-auth Providers (no key required)", noauth, "No-auth"),
|
|
buildSection("OAuth Providers", oauth, "OAuth"),
|
|
buildSection("Web Cookie Providers", webCookie, "Web cookie"),
|
|
buildSection("API Key Providers (paid / paid-with-free-credits)", apiKey, "API key"),
|
|
buildSection("Local Providers", local, "Local"),
|
|
buildSection("Search Providers", search, "Search"),
|
|
buildSection("Audio-only Providers", audio, "Audio"),
|
|
buildSection("Upstream Proxy Providers", upstreamProxy, "Upstream proxy"),
|
|
buildSection("Cloud Agent Providers", cloudAgent, "Cloud agent"),
|
|
buildSection("System Providers", system, "System"),
|
|
];
|
|
|
|
const footer = [
|
|
"## Sources of truth",
|
|
"",
|
|
"- Catalog: [`src/shared/constants/providers.ts`](../../src/shared/constants/providers.ts)",
|
|
"- Registry (per-model details): [`open-sse/config/providerRegistry.ts`](../../open-sse/config/providerRegistry.ts)",
|
|
`- Executors: [\`open-sse/executors/\`](../../open-sse/executors/) (${countExecutorImpls()} implementations)`,
|
|
"- Translators: [`open-sse/translator/`](../../open-sse/translator/)",
|
|
"",
|
|
"## See Also",
|
|
"",
|
|
"- [FREE_TIERS.md](./FREE_TIERS.md) — curated free-tier guide",
|
|
"- [USER_GUIDE.md](../guides/USER_GUIDE.md) — provider setup walkthrough",
|
|
"- [ARCHITECTURE.md](../architecture/ARCHITECTURE.md) — overall architecture",
|
|
"",
|
|
].join("\n");
|
|
|
|
const content = buildHeader(allIds.size) + sections.join("\n") + "\n" + footer;
|
|
fs.writeFileSync(OUT_FILE, content);
|
|
console.log(`✓ Wrote ${OUT_FILE}`);
|
|
console.log(` Providers: ${allIds.size} unique IDs`);
|
|
console.log(
|
|
` Sections: free=${free.length}, noauth=${noauth.length}, oauth=${oauth.length}, ` +
|
|
`web=${webCookie.length}, apikey=${apiKey.length}, local=${local.length}, ` +
|
|
`search=${search.length}, audio=${audio.length}, proxy=${upstreamProxy.length}, ` +
|
|
`cloud=${cloudAgent.length}, system=${system.length}`
|
|
);
|
|
}
|
|
|
|
main();
|