modelalive 1.0.2 → 1.2.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.
@@ -0,0 +1,2 @@
1
+ import type { AliveResult } from "./types.js";
2
+ export declare function alive(model: string, today?: Date): AliveResult;
package/dist/alive.js ADDED
@@ -0,0 +1,54 @@
1
+ import { daysUntil, effectiveStatus, loadRegistry, resolveAlias, } from "./registry.js";
2
+ import { normalizeModel } from "./normalize.js";
3
+ export function alive(model, today = new Date()) {
4
+ const registry = loadRegistry();
5
+ const queried = normalizeModel(model);
6
+ const [canonical, aliased] = resolveAlias(queried, registry);
7
+ const entry = registry.models[canonical];
8
+ if (!entry) {
9
+ return {
10
+ model: canonical,
11
+ queried_model: queried,
12
+ canonical_model: canonical,
13
+ aliased,
14
+ alive: true,
15
+ status: "unknown",
16
+ confidence: "unknown",
17
+ message: "Model not in registry — assumed alive.",
18
+ registry_version: registry.version,
19
+ };
20
+ }
21
+ const status = effectiveStatus(entry, today);
22
+ const sourceKey = entry.source ?? "";
23
+ const sourceMeta = registry.sources[sourceKey];
24
+ const daysLeft = daysUntil(entry.retired_at, today);
25
+ const base = {
26
+ model: canonical,
27
+ queried_model: queried,
28
+ canonical_model: canonical,
29
+ aliased,
30
+ provider: entry.provider,
31
+ deprecated_at: entry.deprecated_at,
32
+ retired_at: entry.retired_at,
33
+ replacement: entry.replacement ?? null,
34
+ breaking_changes: entry.breaking_changes ?? [],
35
+ migrate_url: entry.migrate_url,
36
+ days_until_retirement: daysLeft,
37
+ registry_version: registry.version,
38
+ source_url: sourceMeta?.url,
39
+ source_checked_at: sourceMeta?.checked_at,
40
+ confidence: entry.source ? "verified" : "unknown",
41
+ alive: status !== "retired",
42
+ status: status,
43
+ };
44
+ if (status === "retired") {
45
+ const repl = entry.replacement ? ` Use '${entry.replacement}' instead.` : "";
46
+ base.message = `Model '${canonical}' was retired.${repl}`;
47
+ base.alive = false;
48
+ }
49
+ else if (status === "deprecated") {
50
+ base.message = `Model '${canonical}' is deprecated.`;
51
+ base.alive = true;
52
+ }
53
+ return base;
54
+ }
@@ -0,0 +1,6 @@
1
+ import type { AliveResult } from "./types.js";
2
+ export declare function listExpiring(opts?: {
3
+ withinDays?: number;
4
+ provider?: string;
5
+ today?: Date;
6
+ }): AliveResult[];
@@ -0,0 +1,26 @@
1
+ import { alive } from "./alive.js";
2
+ import { effectiveStatus, loadRegistry, parseDate } from "./registry.js";
3
+ export function listExpiring(opts = {}) {
4
+ const withinDays = opts.withinDays ?? 30;
5
+ const today = opts.today ?? new Date();
6
+ const registry = loadRegistry();
7
+ const results = [];
8
+ for (const [modelId, entry] of Object.entries(registry.models)) {
9
+ if (opts.provider && entry.provider !== opts.provider)
10
+ continue;
11
+ const status = effectiveStatus(entry, today);
12
+ if (status !== "deprecated" && status !== "retired")
13
+ continue;
14
+ const retiredAt = parseDate(entry.retired_at);
15
+ if (!retiredAt)
16
+ continue;
17
+ const ms = retiredAt.getTime() - today.getTime();
18
+ const daysLeft = Math.floor(ms / (1000 * 60 * 60 * 24));
19
+ if (status === "retired" || daysLeft < 0)
20
+ continue;
21
+ if (daysLeft <= withinDays) {
22
+ results.push(alive(modelId, today));
23
+ }
24
+ }
25
+ return results.sort((a, b) => (a.days_until_retirement ?? 9999) - (b.days_until_retirement ?? 9999));
26
+ }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,7 @@
1
- import type { AliveResult } from "./types.js";
2
- export declare function alive(model: string, today?: Date): AliveResult;
3
- export declare function check(model: string, opts?: {
4
- strictUnknown?: boolean;
5
- today?: Date;
6
- }): AliveResult;
1
+ import type { AliveResult, CheckOptions } from "./types.js";
2
+ export { alive } from "./alive.js";
3
+ export declare function check(model: string, opts?: CheckOptions): AliveResult;
4
+ export declare function checkMany(models: string[], today?: Date): AliveResult[];
7
5
  export declare function resolve(model: string, today?: Date): string;
8
6
  export interface ResolveDetail {
9
7
  queried_model: string;
@@ -12,13 +10,12 @@ export interface ResolveDetail {
12
10
  breaking_changes: string[];
13
11
  }
14
12
  export declare function resolveDetail(model: string, today?: Date): ResolveDetail;
15
- export declare function ensure(model: string, opts?: {
16
- strictUnknown?: boolean;
17
- today?: Date;
18
- }): string;
19
- export declare function gate<T>(model: string, fn: (safeModel: string) => T, opts?: {
20
- strictUnknown?: boolean;
21
- today?: Date;
22
- }): T;
13
+ export declare function ensure(model: string, opts?: CheckOptions): string;
14
+ export declare function requireAlive(model: string, opts?: CheckOptions): string;
15
+ export declare function gate<T>(model: string, fn: (safeModel: string) => T, opts?: CheckOptions): T;
23
16
  export * from "./types.js";
24
17
  export { normalizeModel } from "./normalize.js";
18
+ export { listExpiring } from "./expiring.js";
19
+ export { scanPath } from "./scan.js";
20
+ export type { ScanFinding, ScanReport } from "./scan.js";
21
+ export { defaultStrictUnknown, defaultWarnDays, defaultWarnDeprecated, } from "./settings.js";
package/dist/index.js CHANGED
@@ -1,69 +1,36 @@
1
- import { daysUntil, effectiveStatus, loadRegistry, resolveAlias, } from "./registry.js";
1
+ import { alive } from "./alive.js";
2
2
  import { normalizeModel } from "./normalize.js";
3
- import { ModelRetiredError, ModelUnknownError } from "./types.js";
3
+ import { defaultStrictUnknown, defaultWarnDays, defaultWarnDeprecated, } from "./settings.js";
4
+ import { ModelDeprecatedError, ModelExpiringSoonError, ModelRetiredError, ModelUnknownError, } from "./types.js";
4
5
  const MAX_DEPTH = 12;
5
- export function alive(model, today = new Date()) {
6
- const registry = loadRegistry();
7
- const queried = normalizeModel(model);
8
- const [canonical, aliased] = resolveAlias(queried, registry);
9
- const entry = registry.models[canonical];
10
- if (!entry) {
11
- return {
12
- model: canonical,
13
- queried_model: queried,
14
- canonical_model: canonical,
15
- aliased,
16
- alive: true,
17
- status: "unknown",
18
- confidence: "unknown",
19
- message: "Model not in registry — assumed alive.",
20
- registry_version: registry.version,
21
- };
22
- }
23
- const status = effectiveStatus(entry, today);
24
- const sourceKey = entry.source ?? "";
25
- const sourceMeta = registry.sources[sourceKey];
26
- const daysLeft = daysUntil(entry.retired_at, today);
27
- const base = {
28
- model: canonical,
29
- queried_model: queried,
30
- canonical_model: canonical,
31
- aliased,
32
- provider: entry.provider,
33
- deprecated_at: entry.deprecated_at,
34
- retired_at: entry.retired_at,
35
- replacement: entry.replacement ?? null,
36
- breaking_changes: entry.breaking_changes ?? [],
37
- migrate_url: entry.migrate_url,
38
- days_until_retirement: daysLeft,
39
- registry_version: registry.version,
40
- source_url: sourceMeta?.url,
41
- source_checked_at: sourceMeta?.checked_at,
42
- confidence: entry.source ? "verified" : "unknown",
43
- alive: status !== "retired",
44
- status: status,
45
- };
46
- if (status === "retired") {
47
- const repl = entry.replacement ? ` Use '${entry.replacement}' instead.` : "";
48
- base.message = `Model '${canonical}' was retired.${repl}`;
49
- base.alive = false;
50
- }
51
- else if (status === "deprecated") {
52
- base.message = `Model '${canonical}' is deprecated.`;
53
- base.alive = true;
54
- }
55
- return base;
56
- }
6
+ export { alive } from "./alive.js";
57
7
  export function check(model, opts = {}) {
58
- const result = alive(model, opts.today);
59
- if (opts.strictUnknown && result.status === "unknown") {
8
+ const strictUnknown = opts.strictUnknown ?? defaultStrictUnknown();
9
+ const warnDeprecated = opts.warnDeprecated ?? defaultWarnDeprecated();
10
+ const warnDays = opts.warnDays ?? defaultWarnDays();
11
+ const today = opts.today;
12
+ const result = alive(model, today);
13
+ if (strictUnknown && result.status === "unknown") {
60
14
  throw new ModelUnknownError(result);
61
15
  }
62
16
  if (result.status === "retired") {
63
17
  throw new ModelRetiredError(result);
64
18
  }
19
+ if (warnDeprecated && result.status === "deprecated") {
20
+ throw new ModelDeprecatedError(result);
21
+ }
22
+ if (warnDays != null &&
23
+ result.status === "deprecated" &&
24
+ result.days_until_retirement != null &&
25
+ result.days_until_retirement >= 0 &&
26
+ result.days_until_retirement <= warnDays) {
27
+ throw new ModelExpiringSoonError(result);
28
+ }
65
29
  return result;
66
30
  }
31
+ export function checkMany(models, today = new Date()) {
32
+ return models.map((m) => alive(m, today));
33
+ }
67
34
  export function resolve(model, today = new Date()) {
68
35
  return resolveDetail(model, today).resolved;
69
36
  }
@@ -121,17 +88,38 @@ export function resolveDetail(model, today = new Date()) {
121
88
  };
122
89
  }
123
90
  export function ensure(model, opts = {}) {
124
- const result = alive(model, opts.today);
125
- if (opts.strictUnknown && result.status === "unknown") {
91
+ const strictUnknown = opts.strictUnknown ?? defaultStrictUnknown();
92
+ const warnDeprecated = opts.warnDeprecated ?? defaultWarnDeprecated();
93
+ const warnDays = opts.warnDays ?? defaultWarnDays();
94
+ const today = opts.today;
95
+ const result = alive(model, today);
96
+ if (strictUnknown && result.status === "unknown") {
126
97
  throw new ModelUnknownError(result);
127
98
  }
128
99
  if (result.status === "retired" && !result.replacement) {
129
100
  throw new ModelRetiredError(result);
130
101
  }
131
- return resolve(model, opts.today);
102
+ if (warnDeprecated && result.status === "deprecated") {
103
+ throw new ModelDeprecatedError(result);
104
+ }
105
+ if (warnDays != null &&
106
+ result.status === "deprecated" &&
107
+ result.days_until_retirement != null &&
108
+ result.days_until_retirement >= 0 &&
109
+ result.days_until_retirement <= warnDays) {
110
+ throw new ModelExpiringSoonError(result);
111
+ }
112
+ return resolve(model, today);
113
+ }
114
+ export function requireAlive(model, opts = {}) {
115
+ check(model, opts);
116
+ return model;
132
117
  }
133
118
  export function gate(model, fn, opts = {}) {
134
119
  return fn(ensure(model, opts));
135
120
  }
136
121
  export * from "./types.js";
137
122
  export { normalizeModel } from "./normalize.js";
123
+ export { listExpiring } from "./expiring.js";
124
+ export { scanPath } from "./scan.js";
125
+ export { defaultStrictUnknown, defaultWarnDays, defaultWarnDeprecated, } from "./settings.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,42 @@
1
+ import assert from "node:assert/strict";
2
+ import { alive, check, checkMany, defaultStrictUnknown, ensure, gate, listExpiring, normalizeModel, resolve, resolveDetail, scanPath, } from "./index.js";
3
+ import { mkdtempSync, writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { tmpdir } from "node:os";
6
+ import { ModelRetiredError, ModelUnknownError, } from "./types.js";
7
+ // Core lifecycle
8
+ assert.equal(alive("claude-sonnet-4-20250514").status, "retired");
9
+ assert.equal(resolve("claude-sonnet-4-20250514"), "claude-sonnet-4-6");
10
+ assert.equal(ensure("claude-sonnet-4-20250514"), "claude-sonnet-4-6");
11
+ assert.equal(alive("claude-sonnet-4-6").status, "active");
12
+ const detail = resolveDetail("claude-opus-4-20250514");
13
+ assert.equal(detail.resolved, "claude-opus-4-8");
14
+ assert.ok(detail.breaking_changes.length >= 1);
15
+ assert.equal(normalizeModel("ft:gpt-4o-mini:org:foo:bar"), "gpt-4o-mini");
16
+ // Bedrock host entry
17
+ const bedrock = alive("anthropic.claude-sonnet-4-6-v1:0");
18
+ assert.equal(bedrock.provider, "bedrock");
19
+ assert.equal(bedrock.status, "active");
20
+ // Azure host entry
21
+ const azure = alive("azure/gpt-4o");
22
+ assert.equal(azure.provider, "azure");
23
+ // OpenRouter crosswalk
24
+ assert.equal(resolve("anthropic/claude-sonnet-4-6"), "claude-sonnet-4-6");
25
+ const gated = gate("gemini-2.0-flash", (safe) => safe);
26
+ assert.equal(gated, "gemini-3.5-flash");
27
+ // checkMany
28
+ assert.equal(checkMany(["gpt-4o", "claude-sonnet-4-6"]).length, 2);
29
+ // listExpiring
30
+ const expiring = listExpiring({ withinDays: 365, provider: "anthropic" });
31
+ assert.ok(Array.isArray(expiring));
32
+ // scanPath
33
+ const dir = mkdtempSync(join(tmpdir(), "modelalive-"));
34
+ writeFileSync(join(dir, "app.py"), 'MODEL = "claude-sonnet-4-20250514"\n');
35
+ const scan = scanPath(dir);
36
+ assert.ok(scan.findings.length >= 1);
37
+ // Errors
38
+ assert.throws(() => check("totally-unknown-model-xyz", { strictUnknown: true }), ModelUnknownError);
39
+ assert.throws(() => check("claude-sonnet-4-20250514"), ModelRetiredError);
40
+ // env defaults (undefined when unset in test env)
41
+ assert.equal(typeof defaultStrictUnknown(), "boolean");
42
+ console.log("modelalive js parity: ok");
package/dist/scan.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export interface ScanFinding {
2
+ path: string;
3
+ line: number;
4
+ model: string;
5
+ status: string;
6
+ replacement?: string | null;
7
+ alive: boolean;
8
+ }
9
+ export interface ScanReport {
10
+ root: string;
11
+ scannedFiles: number;
12
+ findings: ScanFinding[];
13
+ }
14
+ export declare function scanPath(root: string, today?: Date): ScanReport;
package/dist/scan.js ADDED
@@ -0,0 +1,111 @@
1
+ import { alive } from "./alive.js";
2
+ import { readdirSync, readFileSync, statSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ const SKIP_DIRS = new Set([
5
+ ".git",
6
+ ".venv",
7
+ "venv",
8
+ "node_modules",
9
+ "__pycache__",
10
+ ".pytest_cache",
11
+ "dist",
12
+ "build",
13
+ ".eggs",
14
+ ]);
15
+ const EXTENSIONS = new Set([
16
+ ".py",
17
+ ".ts",
18
+ ".tsx",
19
+ ".js",
20
+ ".jsx",
21
+ ".json",
22
+ ".yaml",
23
+ ".yml",
24
+ ".toml",
25
+ ".env",
26
+ ".md",
27
+ ".sh",
28
+ ]);
29
+ const PATTERNS = [
30
+ /['"](claude-[a-zA-Z0-9._-]{3,128})['"]/g,
31
+ /['"](gpt-[a-zA-Z0-9._-]{3,128})['"]/g,
32
+ /['"](gemini-[a-zA-Z0-9._-]{3,128})['"]/g,
33
+ /['"](o[0-9]-[a-zA-Z0-9._-]{3,128})['"]/g,
34
+ /['"](llama-[a-zA-Z0-9._-]{3,128})['"]/g,
35
+ /['"](grok-[a-zA-Z0-9._-]{3,128})['"]/g,
36
+ /['"](deepseek-[a-zA-Z0-9._-]{3,128})['"]/g,
37
+ /['"](mistral-[a-zA-Z0-9._-]{3,128})['"]/g,
38
+ /['"](qwen[a-zA-Z0-9._-]{0,128})['"]/g,
39
+ /['"](anthropic\.claude-[a-zA-Z0-9._:-]{3,128})['"]/g,
40
+ /['"]((?:anthropic|openai|google|meta-llama|qwen|deepseek|mistral|x-ai)\/[a-zA-Z0-9._:-]{3,128})['"]/g,
41
+ /model\s*[=:]\s*['"]([a-zA-Z0-9][a-zA-Z0-9._:/-]{2,127})['"]/g,
42
+ ];
43
+ function walk(dir, files = []) {
44
+ for (const name of readdirSync(dir)) {
45
+ const path = join(dir, name);
46
+ const parts = path.split(/[/\\]/);
47
+ if (parts.some((p) => SKIP_DIRS.has(p)))
48
+ continue;
49
+ const st = statSync(path);
50
+ if (st.isDirectory())
51
+ walk(path, files);
52
+ else
53
+ files.push(path);
54
+ }
55
+ return files;
56
+ }
57
+ function shouldScan(path) {
58
+ if (path.endsWith(".min.js") || path.endsWith(".map"))
59
+ return false;
60
+ const ext = path.slice(path.lastIndexOf("."));
61
+ return EXTENSIONS.has(ext) || path.endsWith("Dockerfile") || path.endsWith(".env");
62
+ }
63
+ export function scanPath(root, today = new Date()) {
64
+ const report = { root, scannedFiles: 0, findings: [] };
65
+ const seen = new Set();
66
+ for (const path of walk(root)) {
67
+ if (!shouldScan(path))
68
+ continue;
69
+ let text;
70
+ try {
71
+ text = readFileSync(path, "utf-8");
72
+ }
73
+ catch {
74
+ continue;
75
+ }
76
+ report.scannedFiles += 1;
77
+ const lines = text.split(/\r?\n/);
78
+ for (let i = 0; i < lines.length; i++) {
79
+ const line = lines[i];
80
+ for (const pattern of PATTERNS) {
81
+ pattern.lastIndex = 0;
82
+ let match;
83
+ while ((match = pattern.exec(line)) !== null) {
84
+ const model = match[1];
85
+ const key = `${path}:${i + 1}:${model}`;
86
+ if (seen.has(key))
87
+ continue;
88
+ seen.add(key);
89
+ let result;
90
+ try {
91
+ result = alive(model, today);
92
+ }
93
+ catch {
94
+ continue;
95
+ }
96
+ if (result.status === "active")
97
+ continue;
98
+ report.findings.push({
99
+ path: path.startsWith(root) ? path.slice(root.length + 1) : path,
100
+ line: i + 1,
101
+ model,
102
+ status: result.status,
103
+ replacement: result.replacement,
104
+ alive: result.alive,
105
+ });
106
+ }
107
+ }
108
+ }
109
+ }
110
+ return report;
111
+ }
@@ -0,0 +1,5 @@
1
+ /** Environment-driven defaults (parity with Python MODELALIVE_*). */
2
+ export declare function envFlag(name: string, defaultValue?: boolean): boolean;
3
+ export declare function defaultStrictUnknown(): boolean;
4
+ export declare function defaultWarnDeprecated(): boolean;
5
+ export declare function defaultWarnDays(): number | undefined;
@@ -0,0 +1,20 @@
1
+ /** Environment-driven defaults (parity with Python MODELALIVE_*). */
2
+ export function envFlag(name, defaultValue = false) {
3
+ const raw = (process.env[name] ?? "").trim().toLowerCase();
4
+ if (!raw)
5
+ return defaultValue;
6
+ return ["1", "true", "yes", "on"].includes(raw);
7
+ }
8
+ export function defaultStrictUnknown() {
9
+ return envFlag("MODELALIVE_STRICT");
10
+ }
11
+ export function defaultWarnDeprecated() {
12
+ return envFlag("MODELALIVE_WARN_DEPRECATED");
13
+ }
14
+ export function defaultWarnDays() {
15
+ const raw = (process.env["MODELALIVE_WARN_DAYS"] ?? "").trim();
16
+ if (!raw)
17
+ return undefined;
18
+ const n = Number.parseInt(raw, 10);
19
+ return Number.isFinite(n) && n >= 0 ? n : undefined;
20
+ }
@@ -8,7 +8,7 @@ const detail = resolveDetail("claude-opus-4-20250514");
8
8
  assert.equal(detail.resolved, "claude-opus-4-8");
9
9
  assert.ok(detail.breaking_changes.length >= 1);
10
10
  assert.equal(normalizeModel("ft:gpt-4o-mini:org:foo:bar"), "gpt-4o-mini");
11
- assert.equal(alive("anthropic.claude-sonnet-4-6-v1:0").canonical_model, "claude-sonnet-4-6");
11
+ assert.equal(alive("anthropic.claude-sonnet-4-6-v1:0").provider, "bedrock");
12
12
  const gated = gate("gemini-2.0-flash", (safe) => safe);
13
13
  assert.equal(gated, "gemini-3.5-flash");
14
14
  console.log("modelalive js: ok");
package/dist/types.d.ts CHANGED
@@ -46,3 +46,17 @@ export declare class ModelUnknownError extends Error {
46
46
  readonly result: AliveResult;
47
47
  constructor(result: AliveResult);
48
48
  }
49
+ export declare class ModelDeprecatedError extends Error {
50
+ readonly result: AliveResult;
51
+ constructor(result: AliveResult);
52
+ }
53
+ export declare class ModelExpiringSoonError extends Error {
54
+ readonly result: AliveResult;
55
+ constructor(result: AliveResult);
56
+ }
57
+ export interface CheckOptions {
58
+ strictUnknown?: boolean | null;
59
+ warnDeprecated?: boolean | null;
60
+ warnDays?: number | null;
61
+ today?: Date;
62
+ }
package/dist/types.js CHANGED
@@ -14,3 +14,19 @@ export class ModelUnknownError extends Error {
14
14
  this.name = "ModelUnknownError";
15
15
  }
16
16
  }
17
+ export class ModelDeprecatedError extends Error {
18
+ result;
19
+ constructor(result) {
20
+ super(result.message ?? `Model ${result.model} is deprecated`);
21
+ this.result = result;
22
+ this.name = "ModelDeprecatedError";
23
+ }
24
+ }
25
+ export class ModelExpiringSoonError extends Error {
26
+ result;
27
+ constructor(result) {
28
+ super(result.message ?? `Model ${result.model} retires soon`);
29
+ this.result = result;
30
+ this.name = "ModelExpiringSoonError";
31
+ }
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "modelalive",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "description": "Pre-flight check: is this LLM model ID still alive?",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -15,7 +15,7 @@
15
15
  "scripts": {
16
16
  "build": "tsc && cp ../registry/models.json registry.json",
17
17
  "prebuild": "cp ../registry/models.json registry.json",
18
- "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js 2>/dev/null || npm run build && node --test dist/test/*.js"
18
+ "test": "npm run build && node --test dist/smoke.test.js dist/parity.test.js"
19
19
  },
20
20
  "keywords": ["llm", "anthropic", "openai", "gemini", "deprecation", "model-id"],
21
21
  "license": "MIT",
package/registry.json CHANGED
@@ -16,19 +16,19 @@
16
16
  },
17
17
  "groq": {
18
18
  "url": "https://console.groq.com/docs/deprecations",
19
- "checked_at": "2026-06-28"
19
+ "checked_at": "2026-06-29"
20
20
  },
21
21
  "bedrock": {
22
22
  "url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
23
- "checked_at": "2026-06-28"
23
+ "checked_at": "2026-06-29"
24
24
  },
25
25
  "mistral": {
26
26
  "url": "https://docs.mistral.ai/getting-started/models/models_overview/",
27
- "checked_at": "2026-06-28"
27
+ "checked_at": "2026-06-29"
28
28
  },
29
29
  "azure": {
30
30
  "url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
31
- "checked_at": "2026-06-28"
31
+ "checked_at": "2026-06-29"
32
32
  },
33
33
  "cerebras": {
34
34
  "url": "https://inference-docs.cerebras.ai/models/overview",
@@ -87,21 +87,29 @@
87
87
  "claude-3-5-sonnet-latest": "claude-3-5-sonnet-20241022",
88
88
  "claude-3-5-haiku-latest": "claude-3-5-haiku-20241022",
89
89
  "claude-3-opus-latest": "claude-3-opus-20240229",
90
- "azure/gpt-4o": "gpt-4o",
91
- "azure/gpt-4o-mini": "gpt-4o-mini",
92
- "azure/gpt-5.5": "gpt-5.5",
93
- "azure/o3": "o3",
94
- "azure/o4-mini": "o4-mini",
95
- "anthropic.claude-sonnet-4-6-v1:0": "claude-sonnet-4-6",
96
- "anthropic.claude-sonnet-4-20250514-v1:0": "claude-sonnet-4-20250514",
97
- "anthropic.claude-opus-4-8-v1:0": "claude-opus-4-8",
98
- "anthropic.claude-opus-4-20250514-v1:0": "claude-opus-4-20250514",
99
- "anthropic.claude-3-5-sonnet-20241022-v2:0": "claude-3-5-sonnet-20241022",
100
- "anthropic.claude-3-5-haiku-20241022-v1:0": "claude-3-5-haiku-20241022",
101
- "anthropic.claude-3-opus-20240229-v1:0": "claude-3-opus-20240229",
102
- "us.anthropic.claude-sonnet-4-6-v1:0": "claude-sonnet-4-6",
103
- "eu.anthropic.claude-sonnet-4-6-v1:0": "claude-sonnet-4-6",
104
- "amazon.titan-text-premier-v1:0": "amazon.titan-text-premier-v1",
90
+ "us.anthropic.claude-sonnet-4-6-v1:0": "anthropic.claude-sonnet-4-6-v1:0",
91
+ "eu.anthropic.claude-sonnet-4-6-v1:0": "anthropic.claude-sonnet-4-6-v1:0",
92
+ "us.anthropic.claude-opus-4-8-v1:0": "anthropic.claude-opus-4-8-v1:0",
93
+ "eu.anthropic.claude-opus-4-8-v1:0": "anthropic.claude-opus-4-8-v1:0",
94
+ "us.anthropic.claude-3-5-sonnet-20241022-v2:0": "anthropic.claude-3-5-sonnet-20241022-v2:0",
95
+ "anthropic.claude-sonnet-4-6-v1": "anthropic.claude-sonnet-4-6-v1:0",
96
+ "anthropic.claude-sonnet-4-20250514-v1": "anthropic.claude-sonnet-4-20250514-v1:0",
97
+ "anthropic.claude-opus-4-8-v1": "anthropic.claude-opus-4-8-v1:0",
98
+ "anthropic.claude-opus-4-20250514-v1": "anthropic.claude-opus-4-20250514-v1:0",
99
+ "anthropic.claude-haiku-4-5-20251001-v1": "anthropic.claude-haiku-4-5-20251001-v1:0",
100
+ "anthropic.claude-3-5-sonnet-20241022-v2": "anthropic.claude-3-5-sonnet-20241022-v2:0",
101
+ "anthropic.claude-3-5-haiku-20241022-v1": "anthropic.claude-3-5-haiku-20241022-v1:0",
102
+ "anthropic.claude-3-opus-20240229-v1": "anthropic.claude-3-opus-20240229-v1:0",
103
+ "anthropic.claude-3-sonnet-20240229-v1": "anthropic.claude-3-sonnet-20240229-v1:0",
104
+ "anthropic.claude-3-haiku-20240307-v1": "anthropic.claude-3-haiku-20240307-v1:0",
105
+ "meta.llama3-70b-instruct-v1": "meta.llama3-70b-instruct-v1:0",
106
+ "meta.llama3-8b-instruct-v1": "meta.llama3-8b-instruct-v1:0",
107
+ "amazon.titan-text-premier-v1": "amazon.titan-text-premier-v1:0",
108
+ "amazon.nova-pro-v1": "amazon.nova-pro-v1:0",
109
+ "amazon.nova-lite-v1": "amazon.nova-lite-v1:0",
110
+ "cohere.command-r-v1": "cohere.command-r-v1:0",
111
+ "cohere.command-r-plus-v1": "cohere.command-r-plus-v1:0",
112
+ "mistral.mistral-large-2402-v1": "mistral.mistral-large-2402-v1:0",
105
113
  "deepseek/deepseek-chat": "deepseek-chat",
106
114
  "deepseek/deepseek-reasoner": "deepseek-reasoner",
107
115
  "deepseek-r1-0528": "deepseek-r1",
@@ -4991,6 +4999,350 @@
4991
4999
  "breaking_changes": [],
4992
5000
  "migrate_url": "https://docs.fireworks.ai/updates/changelog",
4993
5001
  "source": "fireworks"
5002
+ },
5003
+ "azure/gpt-5.5": {
5004
+ "provider": "azure",
5005
+ "status": "active",
5006
+ "deprecated_at": null,
5007
+ "retired_at": null,
5008
+ "replacement": null,
5009
+ "breaking_changes": [],
5010
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5011
+ "source": "azure",
5012
+ "notes": "Host entry for gpt-5.5"
5013
+ },
5014
+ "azure/gpt-5.5-pro": {
5015
+ "provider": "azure",
5016
+ "status": "active",
5017
+ "deprecated_at": null,
5018
+ "retired_at": null,
5019
+ "replacement": null,
5020
+ "breaking_changes": [],
5021
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5022
+ "source": "azure",
5023
+ "notes": "Host entry for gpt-5.5-pro"
5024
+ },
5025
+ "azure/gpt-5.4-mini": {
5026
+ "provider": "azure",
5027
+ "status": "active",
5028
+ "deprecated_at": null,
5029
+ "retired_at": null,
5030
+ "replacement": null,
5031
+ "breaking_changes": [],
5032
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5033
+ "source": "azure",
5034
+ "notes": "Host entry for gpt-5.4-mini"
5035
+ },
5036
+ "azure/gpt-4o": {
5037
+ "provider": "azure",
5038
+ "status": "active",
5039
+ "deprecated_at": null,
5040
+ "retired_at": null,
5041
+ "replacement": null,
5042
+ "breaking_changes": [],
5043
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5044
+ "source": "azure",
5045
+ "notes": "Host entry for gpt-4o"
5046
+ },
5047
+ "azure/gpt-4o-mini": {
5048
+ "provider": "azure",
5049
+ "status": "active",
5050
+ "deprecated_at": null,
5051
+ "retired_at": null,
5052
+ "replacement": null,
5053
+ "breaking_changes": [],
5054
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5055
+ "source": "azure",
5056
+ "notes": "Host entry for gpt-4o-mini"
5057
+ },
5058
+ "azure/o3": {
5059
+ "provider": "azure",
5060
+ "status": "active",
5061
+ "deprecated_at": null,
5062
+ "retired_at": null,
5063
+ "replacement": null,
5064
+ "breaking_changes": [],
5065
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5066
+ "source": "azure",
5067
+ "notes": "Host entry for o3"
5068
+ },
5069
+ "azure/o3-mini": {
5070
+ "provider": "azure",
5071
+ "status": "active",
5072
+ "deprecated_at": null,
5073
+ "retired_at": null,
5074
+ "replacement": null,
5075
+ "breaking_changes": [],
5076
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5077
+ "source": "azure",
5078
+ "notes": "Host entry for o3-mini"
5079
+ },
5080
+ "azure/o4-mini": {
5081
+ "provider": "azure",
5082
+ "status": "active",
5083
+ "deprecated_at": null,
5084
+ "retired_at": null,
5085
+ "replacement": null,
5086
+ "breaking_changes": [],
5087
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5088
+ "source": "azure",
5089
+ "notes": "Host entry for o4-mini"
5090
+ },
5091
+ "azure/text-embedding-3-large": {
5092
+ "provider": "azure",
5093
+ "status": "active",
5094
+ "replacement": null,
5095
+ "breaking_changes": [],
5096
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5097
+ "source": "azure",
5098
+ "notes": "Host entry — canonical model pending full crosswalk"
5099
+ },
5100
+ "azure/text-embedding-3-small": {
5101
+ "provider": "azure",
5102
+ "status": "active",
5103
+ "replacement": null,
5104
+ "breaking_changes": [],
5105
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5106
+ "source": "azure",
5107
+ "notes": "Host entry — canonical model pending full crosswalk"
5108
+ },
5109
+ "azure/claude-sonnet-4-6": {
5110
+ "provider": "azure",
5111
+ "status": "active",
5112
+ "deprecated_at": null,
5113
+ "retired_at": null,
5114
+ "replacement": null,
5115
+ "breaking_changes": [],
5116
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5117
+ "source": "azure",
5118
+ "notes": "Host entry for claude-sonnet-4-6"
5119
+ },
5120
+ "azure/claude-opus-4-8": {
5121
+ "provider": "azure",
5122
+ "status": "active",
5123
+ "deprecated_at": null,
5124
+ "retired_at": null,
5125
+ "replacement": null,
5126
+ "breaking_changes": [
5127
+ "temperature, top_p, and top_k return 400 on Claude Opus 4.7+ — omit these parameters"
5128
+ ],
5129
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5130
+ "source": "azure",
5131
+ "notes": "Host entry for claude-opus-4-8"
5132
+ },
5133
+ "azure/claude-haiku-4-5": {
5134
+ "provider": "azure",
5135
+ "status": "active",
5136
+ "deprecated_at": null,
5137
+ "retired_at": null,
5138
+ "replacement": null,
5139
+ "breaking_changes": [],
5140
+ "migrate_url": "https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/model-retirements",
5141
+ "source": "azure",
5142
+ "notes": "Host entry for claude-haiku-4-5-20251001"
5143
+ },
5144
+ "anthropic.claude-sonnet-4-6-v1:0": {
5145
+ "provider": "bedrock",
5146
+ "status": "active",
5147
+ "deprecated_at": null,
5148
+ "retired_at": null,
5149
+ "replacement": null,
5150
+ "breaking_changes": [],
5151
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5152
+ "source": "bedrock",
5153
+ "notes": "Host entry for claude-sonnet-4-6"
5154
+ },
5155
+ "anthropic.claude-sonnet-4-20250514-v1:0": {
5156
+ "provider": "bedrock",
5157
+ "status": "retired",
5158
+ "deprecated_at": "2026-04-14",
5159
+ "retired_at": "2026-06-15",
5160
+ "replacement": "anthropic.claude-sonnet-4-6-v1:0",
5161
+ "breaking_changes": [],
5162
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5163
+ "source": "bedrock",
5164
+ "notes": "Host entry for claude-sonnet-4-20250514"
5165
+ },
5166
+ "anthropic.claude-opus-4-8-v1:0": {
5167
+ "provider": "bedrock",
5168
+ "status": "active",
5169
+ "deprecated_at": null,
5170
+ "retired_at": null,
5171
+ "replacement": null,
5172
+ "breaking_changes": [
5173
+ "temperature, top_p, and top_k return 400 on Claude Opus 4.7+ — omit these parameters"
5174
+ ],
5175
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5176
+ "source": "bedrock",
5177
+ "notes": "Host entry for claude-opus-4-8"
5178
+ },
5179
+ "anthropic.claude-opus-4-20250514-v1:0": {
5180
+ "provider": "bedrock",
5181
+ "status": "retired",
5182
+ "deprecated_at": "2026-04-14",
5183
+ "retired_at": "2026-06-15",
5184
+ "replacement": "anthropic.claude-opus-4-8-v1:0",
5185
+ "breaking_changes": [
5186
+ "temperature, top_p, and top_k are rejected on Claude Opus 4.7+ — remove before migrating"
5187
+ ],
5188
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5189
+ "source": "bedrock",
5190
+ "notes": "Host entry for claude-opus-4-20250514"
5191
+ },
5192
+ "anthropic.claude-haiku-4-5-20251001-v1:0": {
5193
+ "provider": "bedrock",
5194
+ "status": "active",
5195
+ "deprecated_at": null,
5196
+ "retired_at": null,
5197
+ "replacement": null,
5198
+ "breaking_changes": [],
5199
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5200
+ "source": "bedrock",
5201
+ "notes": "Host entry for claude-haiku-4-5-20251001"
5202
+ },
5203
+ "anthropic.claude-3-5-sonnet-20241022-v2:0": {
5204
+ "provider": "bedrock",
5205
+ "status": "retired",
5206
+ "deprecated_at": "2025-08-13",
5207
+ "retired_at": "2025-10-28",
5208
+ "replacement": "anthropic.claude-sonnet-4-6-v1:0",
5209
+ "breaking_changes": [],
5210
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5211
+ "source": "bedrock",
5212
+ "notes": "Host entry for claude-3-5-sonnet-20241022"
5213
+ },
5214
+ "anthropic.claude-3-5-haiku-20241022-v1:0": {
5215
+ "provider": "bedrock",
5216
+ "status": "retired",
5217
+ "deprecated_at": "2025-12-19",
5218
+ "retired_at": "2026-02-19",
5219
+ "replacement": "anthropic.claude-haiku-4-5-20251001-v1:0",
5220
+ "breaking_changes": [],
5221
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5222
+ "source": "bedrock",
5223
+ "notes": "Host entry for claude-3-5-haiku-20241022"
5224
+ },
5225
+ "anthropic.claude-3-opus-20240229-v1:0": {
5226
+ "provider": "bedrock",
5227
+ "status": "retired",
5228
+ "deprecated_at": "2025-06-30",
5229
+ "retired_at": "2026-01-05",
5230
+ "replacement": "anthropic.claude-opus-4-8-v1:0",
5231
+ "breaking_changes": [],
5232
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5233
+ "source": "bedrock",
5234
+ "notes": "Host entry for claude-3-opus-20240229"
5235
+ },
5236
+ "anthropic.claude-3-sonnet-20240229-v1:0": {
5237
+ "provider": "bedrock",
5238
+ "status": "retired",
5239
+ "deprecated_at": "2025-01-21",
5240
+ "retired_at": "2025-07-21",
5241
+ "replacement": "anthropic.claude-sonnet-4-6-v1:0",
5242
+ "breaking_changes": [],
5243
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5244
+ "source": "bedrock",
5245
+ "notes": "Host entry for claude-3-sonnet-20240229"
5246
+ },
5247
+ "anthropic.claude-3-haiku-20240307-v1:0": {
5248
+ "provider": "bedrock",
5249
+ "status": "retired",
5250
+ "deprecated_at": "2026-02-19",
5251
+ "retired_at": "2026-04-20",
5252
+ "replacement": "anthropic.claude-haiku-4-5-20251001-v1:0",
5253
+ "breaking_changes": [],
5254
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5255
+ "source": "bedrock",
5256
+ "notes": "Host entry for claude-3-haiku-20240307"
5257
+ },
5258
+ "meta.llama3-70b-instruct-v1:0": {
5259
+ "provider": "bedrock",
5260
+ "status": "active",
5261
+ "deprecated_at": null,
5262
+ "retired_at": null,
5263
+ "replacement": null,
5264
+ "breaking_changes": [],
5265
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5266
+ "source": "bedrock",
5267
+ "notes": "Host entry for meta-llama/Llama-3.3-70B-Instruct"
5268
+ },
5269
+ "meta.llama3-8b-instruct-v1:0": {
5270
+ "provider": "bedrock",
5271
+ "status": "active",
5272
+ "replacement": null,
5273
+ "breaking_changes": [],
5274
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5275
+ "source": "bedrock",
5276
+ "notes": "Host entry — canonical model pending full crosswalk"
5277
+ },
5278
+ "amazon.titan-text-premier-v1:0": {
5279
+ "provider": "bedrock",
5280
+ "status": "active",
5281
+ "deprecated_at": null,
5282
+ "retired_at": null,
5283
+ "replacement": null,
5284
+ "breaking_changes": [],
5285
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5286
+ "source": "bedrock",
5287
+ "notes": "Host entry for amazon.titan-text-premier-v1"
5288
+ },
5289
+ "amazon.nova-pro-v1:0": {
5290
+ "provider": "bedrock",
5291
+ "status": "active",
5292
+ "replacement": null,
5293
+ "breaking_changes": [],
5294
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5295
+ "source": "bedrock",
5296
+ "notes": "Host entry — canonical model pending full crosswalk"
5297
+ },
5298
+ "amazon.nova-lite-v1:0": {
5299
+ "provider": "bedrock",
5300
+ "status": "active",
5301
+ "replacement": null,
5302
+ "breaking_changes": [],
5303
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5304
+ "source": "bedrock",
5305
+ "notes": "Host entry — canonical model pending full crosswalk"
5306
+ },
5307
+ "cohere.command-r-v1:0": {
5308
+ "provider": "bedrock",
5309
+ "status": "active",
5310
+ "replacement": null,
5311
+ "breaking_changes": [],
5312
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5313
+ "source": "bedrock",
5314
+ "notes": "Host entry — canonical model pending full crosswalk"
5315
+ },
5316
+ "cohere.command-r-plus-v1:0": {
5317
+ "provider": "bedrock",
5318
+ "status": "retired",
5319
+ "deprecated_at": "2025-09-01",
5320
+ "retired_at": "2026-03-01",
5321
+ "replacement": "command-r-plus-08-2024",
5322
+ "breaking_changes": [],
5323
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5324
+ "source": "bedrock",
5325
+ "notes": "Host entry for command-r-plus"
5326
+ },
5327
+ "mistral.mistral-large-2402-v1:0": {
5328
+ "provider": "bedrock",
5329
+ "status": "active",
5330
+ "deprecated_at": null,
5331
+ "retired_at": null,
5332
+ "replacement": null,
5333
+ "breaking_changes": [],
5334
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5335
+ "source": "bedrock",
5336
+ "notes": "Host entry for mistral-large-2411"
5337
+ },
5338
+ "mistral.mixtral-8x7b-instruct-v0:1": {
5339
+ "provider": "bedrock",
5340
+ "status": "active",
5341
+ "replacement": null,
5342
+ "breaking_changes": [],
5343
+ "migrate_url": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-lifecycle.html",
5344
+ "source": "bedrock",
5345
+ "notes": "Host entry — canonical model pending full crosswalk"
4994
5346
  }
4995
5347
  }
4996
5348
  }