Compare commits

...

3 Commits

Author SHA1 Message Date
Aiden Cline c8dc9cae24 chore(sync): keep fireworks catalog entries curated 2026-05-21 18:32:00 -05:00
Aiden Cline 964775cf77 chore(sync): standardize fireworks api key env 2026-05-21 18:25:07 -05:00
Aiden Cline 7509cf1797 chore(sync): add fireworks ai provider 2026-05-21 18:18:35 -05:00
4 changed files with 97 additions and 1 deletions
+1
View File
@@ -63,6 +63,7 @@ jobs:
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
GOOGLE_GENERATIVE_AI_API_KEY: ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
CLOUDFLARE_WORKERS_AI_SYNC_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_WORKERS_AI_SYNC_ACCOUNT_ID }}
CLOUDFLARE_WORKERS_AI_SYNC_API_TOKEN: ${{ secrets.CLOUDFLARE_WORKERS_AI_SYNC_API_TOKEN }}
+9 -1
View File
@@ -4,6 +4,7 @@ import { z } from "zod";
import { AuthoredModel, AuthoredModelShape } from "../schema.js";
import { cloudflareWorkersAi } from "./providers/cloudflare-workers-ai.js";
import { fireworksAi } from "./providers/fireworks-ai.js";
import { google } from "./providers/google.js";
import { openrouter } from "./providers/openrouter.js";
import { xai } from "./providers/xai.js";
@@ -47,6 +48,7 @@ export interface SyncProvider<SourceModel> {
name: string;
modelsDir: string;
skipCreates?: boolean;
deleteMissing?: boolean;
sourceID?(model: SourceModel): string;
skippedNotice?(ids: string[]): string[];
fetchModels(): Promise<unknown>;
@@ -71,11 +73,13 @@ export interface SyncResult {
export const providers: {
"cloudflare-workers-ai": SyncProvider<any>;
"fireworks-ai": SyncProvider<any>;
google: SyncProvider<any>;
openrouter: SyncProvider<any>;
xai: SyncProvider<any>;
} = {
"cloudflare-workers-ai": cloudflareWorkersAi,
"fireworks-ai": fireworksAi,
google,
openrouter,
xai,
@@ -84,7 +88,7 @@ export const providers: {
export const groups = {
aggregators: ["openrouter"],
cloudflare: ["cloudflare-workers-ai"],
direct: ["google", "xai"],
direct: ["fireworks-ai", "google", "xai"],
} as const;
type ProviderID = keyof typeof providers;
@@ -183,6 +187,10 @@ export async function syncProvider<SourceModel>(
for (const relativePath of existing.keys()) {
if (desired.has(relativePath)) continue;
if (provider.deleteMissing === false) {
unchanged++;
continue;
}
if (options.newOnly) {
console.log(`Skipping removal in new-only mode: ${relativePath}`);
unchanged++;
@@ -0,0 +1,75 @@
import { z } from "zod";
import type { SyncProvider } from "../index.js";
const API_BASE = "https://api.fireworks.ai/v1";
const FireworksModel = z.object({
name: z.string(),
}).passthrough();
const FireworksResponse = z.object({
models: z.array(FireworksModel).optional(),
nextPageToken: z.string().optional(),
}).passthrough();
type FireworksModel = z.infer<typeof FireworksModel>;
export const fireworksAi = {
id: "fireworks-ai",
name: "Fireworks AI",
modelsDir: "providers/fireworks-ai/models",
skipCreates: true,
deleteMissing: false,
sourceID(model) {
return model.name;
},
skippedNotice(ids) {
if (ids.length === 0) return [];
return [
`${ids.length} Fireworks AI models returned by the API were not created because the Models API does not provide pricing, output token limits, release dates, or complete capability metadata. Existing models are preserved unchanged.`,
`Skipped remote IDs: ${ids.map((id) => `\`${id}\``).join(", ")}`,
];
},
async fetchModels() {
const key = process.env.FIREWORKS_API_KEY;
if (key === undefined) {
throw new Error("Fireworks AI sync requires FIREWORKS_API_KEY");
}
const models: FireworksModel[] = [];
let pageToken: string | undefined;
do {
const url = new URL(`${API_BASE}/accounts/fireworks/models`);
url.searchParams.set("pageSize", "200");
url.searchParams.set("filter", "supports_serverless = true");
if (pageToken !== undefined) url.searchParams.set("pageToken", pageToken);
const response = await fetch(url, {
headers: { Authorization: `Bearer ${key}` },
});
if (!response.ok) {
throw new Error(`Fireworks AI models request failed: ${response.status} ${response.statusText}`);
}
const page = FireworksResponse.parse(await response.json());
models.push(...page.models ?? []);
pageToken = page.nextPageToken || undefined;
} while (pageToken !== undefined);
return { models };
},
parseModels(raw) {
return FireworksResponse.parse(raw).models ?? [];
},
translateModel(model, context) {
const existing = context.existing(model.name);
if (existing === undefined) return undefined;
return {
id: model.name,
model: existing,
};
},
} satisfies SyncProvider<FireworksModel>;
+12
View File
@@ -13,6 +13,7 @@ The grouped sync targets are available for local convenience, but CI syncs each
- `bun models:sync cloudflare-workers-ai` syncs only Cloudflare Workers AI.
- `bun models:sync cloudflare` syncs the Cloudflare sync group.
- `bun models:sync direct` syncs every provider in the `direct` group.
- `bun models:sync fireworks-ai` syncs only Fireworks AI.
- `bun models:sync google` syncs only Google.
- `bun models:sync xai` syncs only xAI.
- `bun models:sync aggregators --dry-run` prints changes without writing model files.
@@ -129,6 +130,17 @@ Cloudflare Workers AI is implemented in `packages/core/src/sync/providers/cloudf
- Model IDs map directly to TOML paths under `providers/cloudflare-workers-ai/models`.
- This sync target does not manage `providers/cloudflare-ai-gateway`, because the AI Gateway `/compat/models` endpoint does not support `format=openrouter` and does not provide enough model metadata for authoritative catalog sync.
## Fireworks AI Notes
Fireworks AI is implemented in `packages/core/src/sync/providers/fireworks-ai.ts`.
- Source endpoint: `https://api.fireworks.ai/v1/accounts/fireworks/models` with `supports_serverless = true`.
- Required auth: `FIREWORKS_API_KEY`.
- Model IDs map directly to TOML paths under `providers/fireworks-ai/models`.
- Existing Fireworks AI models are preserved unchanged because the API does not provide pricing, output token limits, release dates, or enough complete capability metadata for safe catalog rewrites.
- New Fireworks AI API models are reported in `.sync/model-sync-report.md` but not created automatically because the API does not provide enough authoritative metadata for complete catalog entries.
- Local Fireworks AI models missing from the API response are preserved because the API omits curated router entries and non-serverless catalog metadata. Fireworks has a routers API, but the public `accounts/fireworks` routers are not listable with the sync API key.
## Google Notes
Google is implemented in `packages/core/src/sync/providers/google.ts`.