Skip to content
Open
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
102 changes: 74 additions & 28 deletions packages/core/script/generate-helicone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { z } from "zod";
import path from "node:path";
import { mkdir, rm, readdir, stat } from "node:fs/promises";
import { mkdir } from "node:fs/promises";

// Helicone public model registry endpoint
const DEFAULT_ENDPOINT =
Expand Down Expand Up @@ -70,26 +70,51 @@ function boolFromParams(params: string[] | undefined, keys: string[]): boolean {
return keys.some((k) => set.has(k.toLowerCase()));
}

function cleanPrice(p: number): string {
return parseFloat(p.toPrecision(10)).toString();
}

function sanitizeModalities(values: string[] | undefined): string[] {
if (!values) return ["text"]; // default to text
const allowed = new Set(["text", "audio", "image", "video", "pdf"]);
const out = values.map((v) => v.toLowerCase()).filter((v) => allowed.has(v));
return out.length > 0 ? out : ["text"];
}

function formatToml(model: z.infer<typeof ModelItem>) {
// ── Manually curated fields preserved from existing TOML ─────────────────────

interface ExistingModel {
family?: string;
status?: string;
open_weights?: boolean;
release_date?: string;
knowledge?: string;
}

async function loadExistingModel(filePath: string): Promise<ExistingModel | null> {
try {
const file = Bun.file(filePath);
if (!(await file.exists())) return null;
const toml = await import(filePath, { with: { type: "toml" } }).then(
(m) => m.default,
);
return toml as ExistingModel;
} catch {
return null;
}
}

function formatToml(model: z.infer<typeof ModelItem>, existing: ExistingModel | null) {
const ep = pickEndpoint(model);
const pricing = ep?.pricing;

const supported = model.supportedParameters ?? [];

const nowISO = new Date().toISOString().slice(0, 10);
const rdRaw = model.trainingDate ? String(model.trainingDate) : nowISO;
const releaseDate = rdRaw.slice(0, 10);
const lastUpdated = releaseDate;
const knowledge = model.trainingDate
? String(model.trainingDate).slice(0, 7)
: undefined;
const releaseDate = existing?.release_date ?? rdRaw.slice(0, 10);
const knowledge = existing?.knowledge ??
(model.trainingDate ? String(model.trainingDate).slice(0, 7) : undefined);

const attachment = false; // Not exposed by Helicone registry
const temperature = boolFromParams(supported, ["temperature"]);
Expand All @@ -104,14 +129,16 @@ function formatToml(model: z.infer<typeof ModelItem>) {

const lines: string[] = [];
lines.push(`name = "${model.name.replaceAll('"', '\\"')}"`);
if (existing?.family) lines.push(`family = "${existing.family}"`);
lines.push(`release_date = "${releaseDate}"`);
lines.push(`last_updated = "${lastUpdated}"`);
lines.push(`last_updated = "${nowISO}"`);
lines.push(`attachment = ${attachment}`);
lines.push(`reasoning = ${reasoning}`);
lines.push(`temperature = ${temperature}`);
lines.push(`tool_call = ${toolCall}`);
if (knowledge) lines.push(`knowledge = "${knowledge}"`);
lines.push(`open_weights = false`);
lines.push(`open_weights = ${existing?.open_weights ?? false}`);
if (existing?.status) lines.push(`status = "${existing.status}"`);
lines.push("");

if (
Expand All @@ -123,15 +150,15 @@ function formatToml(model: z.infer<typeof ModelItem>) {
(reasoning && pricing.reasoning)) !== undefined
) {
lines.push(`[cost]`);
if (pricing.prompt !== undefined) lines.push(`input = ${pricing.prompt}`);
if (pricing.prompt !== undefined) lines.push(`input = ${cleanPrice(pricing.prompt)}`);
if (pricing.completion !== undefined)
lines.push(`output = ${pricing.completion}`);
lines.push(`output = ${cleanPrice(pricing.completion)}`);
if (reasoning && pricing.reasoning !== undefined)
lines.push(`reasoning = ${pricing.reasoning}`);
lines.push(`reasoning = ${cleanPrice(pricing.reasoning)}`);
if (pricing.cacheRead !== undefined)
lines.push(`cache_read = ${pricing.cacheRead}`);
lines.push(`cache_read = ${cleanPrice(pricing.cacheRead)}`);
if (pricing.cacheWrite !== undefined)
lines.push(`cache_write = ${pricing.cacheWrite}`);
lines.push(`cache_write = ${cleanPrice(pricing.cacheWrite)}`);
lines.push("");
}

Expand Down Expand Up @@ -179,29 +206,48 @@ async function main() {

const models = parsed.data.data.models;

// Clean output directory: remove subfolders and existing TOML files
await mkdir(outDir, { recursive: true });
for (const entry of await readdir(outDir)) {
const p = path.join(outDir, entry);
const st = await stat(p);
if (st.isDirectory()) {
await rm(p, { recursive: true, force: true });
} else if (st.isFile() && entry.endsWith(".toml")) {
await rm(p, { force: true });
}
}
let created = 0;
let updated = 0;
let unchanged = 0;

const apiFilenames = new Set<string>();

for (const m of models) {
const fileSafeId = m.id.replaceAll("/", "-");
const filePath = path.join(outDir, `${fileSafeId}.toml`);
const toml = formatToml(m);
await Bun.write(filePath, toml);
created++;
apiFilenames.add(`${fileSafeId}.toml`);
const existing = await loadExistingModel(filePath);
const newToml = formatToml(m, existing);

if (existing === null) {
await Bun.write(filePath, newToml);
created++;
continue;
}

// Compare ignoring last_updated line — only write if something meaningful changed
const strip = (s: string) => s.replace(/^last_updated = ".+"\n/m, "");
const existingRaw = await Bun.file(filePath).text();

if (strip(newToml) === strip(existingRaw)) {
unchanged++;
} else {
await Bun.write(filePath, newToml);
updated++;
}
}

let orphaned = 0;
for await (const file of new Bun.Glob("*.toml").scan({ cwd: outDir, absolute: false })) {
if (!apiFilenames.has(file)) {
console.log(`Note: ${file} not in Helicone API (kept)`);
orphaned++;
}
}

console.log(
`Generated ${created} model file(s) under providers/helicone/models/*.toml`,
`providers/helicone/models: ${created} created, ${updated} updated, ${unchanged} unchanged, ${orphaned} not in API (kept)`,
);
}

Expand Down
4 changes: 2 additions & 2 deletions providers/helicone/models/claude-3.5-haiku.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Anthropic: Claude 3.5 Haiku"
family = "claude-haiku"
release_date = "2024-10-22"
last_updated = "2024-10-22"
last_updated = "2026-03-03"
attachment = false
reasoning = false
temperature = true
Expand All @@ -10,7 +10,7 @@ knowledge = "2024-10"
open_weights = false

[cost]
input = 0.7999999999999999
input = 0.8
output = 4
cache_read = 0.08
cache_write = 1
Expand Down
4 changes: 2 additions & 2 deletions providers/helicone/models/claude-3.5-sonnet-v2.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Anthropic: Claude 3.5 Sonnet v2"
family = "claude-sonnet"
release_date = "2024-10-22"
last_updated = "2024-10-22"
last_updated = "2026-03-03"
attachment = false
reasoning = false
temperature = true
Expand All @@ -12,7 +12,7 @@ open_weights = false
[cost]
input = 3
output = 15
cache_read = 0.30000000000000004
cache_read = 0.3
cache_write = 3.75

[limit]
Expand Down
4 changes: 2 additions & 2 deletions providers/helicone/models/claude-3.7-sonnet.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Anthropic: Claude 3.7 Sonnet"
family = "claude-sonnet"
release_date = "2025-02-19"
last_updated = "2025-02-19"
last_updated = "2026-03-03"
attachment = false
reasoning = false
temperature = true
Expand All @@ -12,7 +12,7 @@ open_weights = false
[cost]
input = 3
output = 15
cache_read = 0.30000000000000004
cache_read = 0.3
cache_write = 3.75

[limit]
Expand Down
4 changes: 2 additions & 2 deletions providers/helicone/models/claude-4.5-haiku.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Anthropic: Claude 4.5 Haiku"
family = "claude-haiku"
release_date = "2025-10-01"
last_updated = "2025-10-01"
last_updated = "2026-03-03"
attachment = false
reasoning = false
temperature = true
Expand All @@ -12,7 +12,7 @@ open_weights = false
[cost]
input = 1
output = 5
cache_read = 0.09999999999999999
cache_read = 0.1
cache_write = 1.25

[limit]
Expand Down
4 changes: 2 additions & 2 deletions providers/helicone/models/claude-4.5-opus.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Anthropic: Claude Opus 4.5"
family = "claude-opus"
release_date = "2025-11-24"
last_updated = "2025-11-24"
last_updated = "2026-03-03"
attachment = false
reasoning = true
temperature = true
Expand All @@ -12,7 +12,7 @@ open_weights = false
[cost]
input = 5
output = 25
cache_read = 0.50
cache_read = 0.5
cache_write = 6.25

[limit]
Expand Down
4 changes: 2 additions & 2 deletions providers/helicone/models/claude-4.5-sonnet.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Anthropic: Claude Sonnet 4.5"
family = "claude-sonnet"
release_date = "2025-09-29"
last_updated = "2025-09-29"
last_updated = "2026-03-03"
attachment = false
reasoning = true
temperature = true
Expand All @@ -12,7 +12,7 @@ open_weights = false
[cost]
input = 3
output = 15
cache_read = 0.30000000000000004
cache_read = 0.3
cache_write = 3.75

[limit]
Expand Down
23 changes: 23 additions & 0 deletions providers/helicone/models/claude-4.6-opus.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name = "Anthropic: Claude Opus 4.6"
release_date = "2026-02-05"
last_updated = "2026-03-03"
attachment = false
reasoning = true
temperature = true
tool_call = true
knowledge = "2026-02"
open_weights = false

[cost]
input = 5
output = 25
cache_read = 0.5
cache_write = 6.25

[limit]
context = 1000000
output = 64000

[modalities]
input = ["text", "image"]
output = ["text"]
23 changes: 23 additions & 0 deletions providers/helicone/models/claude-4.6-sonnet.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name = "Anthropic: Claude Sonnet 4.6"
release_date = "2026-02-17"
last_updated = "2026-03-03"
attachment = false
reasoning = true
temperature = true
tool_call = true
knowledge = "2026-02"
open_weights = false

[cost]
input = 3
output = 15
cache_read = 0.3
cache_write = 3.75

[limit]
context = 1000000
output = 64000

[modalities]
input = ["text", "image"]
output = ["text"]
4 changes: 2 additions & 2 deletions providers/helicone/models/claude-haiku-4-5-20251001.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Anthropic: Claude 4.5 Haiku (20251001)"
family = "claude-haiku"
release_date = "2025-10-01"
last_updated = "2025-10-01"
last_updated = "2026-03-03"
attachment = false
reasoning = false
temperature = true
Expand All @@ -12,7 +12,7 @@ open_weights = false
[cost]
input = 1
output = 5
cache_read = 0.09999999999999999
cache_read = 0.1
cache_write = 1.25

[limit]
Expand Down
4 changes: 2 additions & 2 deletions providers/helicone/models/claude-sonnet-4-5-20250929.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Anthropic: Claude Sonnet 4.5 (20250929)"
family = "claude-sonnet"
release_date = "2025-09-29"
last_updated = "2025-09-29"
last_updated = "2026-03-03"
attachment = false
reasoning = true
temperature = true
Expand All @@ -12,7 +12,7 @@ open_weights = false
[cost]
input = 3
output = 15
cache_read = 0.30000000000000004
cache_read = 0.3
cache_write = 3.75

[limit]
Expand Down
4 changes: 2 additions & 2 deletions providers/helicone/models/claude-sonnet-4.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Anthropic: Claude Sonnet 4"
family = "claude-sonnet"
release_date = "2025-05-14"
last_updated = "2025-05-14"
last_updated = "2026-03-03"
attachment = false
reasoning = true
temperature = true
Expand All @@ -12,7 +12,7 @@ open_weights = false
[cost]
input = 3
output = 15
cache_read = 0.30000000000000004
cache_read = 0.3
cache_write = 3.75

[limit]
Expand Down
4 changes: 2 additions & 2 deletions providers/helicone/models/deepseek-v3.1-terminus.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "DeepSeek V3.1 Terminus"
family = "deepseek"
release_date = "2025-09-22"
last_updated = "2025-09-22"
last_updated = "2026-03-03"
attachment = false
reasoning = true
temperature = true
Expand All @@ -12,7 +12,7 @@ open_weights = false
[cost]
input = 0.27
output = 1
cache_read = 0.21600000000000003
cache_read = 0.216

[limit]
context = 128000
Expand Down
Loading