model-eol 0.7.0 → 0.8.1
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.
- package/README.md +20 -1
- package/SPEC.md +1 -0
- package/bot/bot.mjs +60 -4
- package/bot/lib/common.mjs +10 -2
- package/bot/lib/eval.mjs +4 -1
- package/check.mjs +2 -1
- package/feeds/anthropic.json +112 -37
- package/feeds/cohere.json +23 -23
- package/feeds/google.json +20 -6
- package/feeds/mistral.json +52 -52
- package/feeds/openai.json +263 -87
- package/lib/feeds.mjs +23 -0
- package/lib/reports.mjs +10 -1
- package/package.json +1 -1
- package/schema/model-eol.bot-config.schema.json +1 -1
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ format instead of each scraping the same pages.
|
|
|
36
36
|
replacement, `distributions` for per-channel lifecycles, and publisher `policy`
|
|
37
37
|
floors. It is small enough that a provider could serve it at
|
|
38
38
|
`/.well-known/model-eol.json` in an afternoon.
|
|
39
|
-
- **`feeds/`** - <!-- feeds-status -->Amazon (4 entries), Anthropic (
|
|
39
|
+
- **`feeds/`** - <!-- feeds-status -->Amazon (4 entries), Anthropic (33 entries), Cohere (12 entries), Google (96 entries), Mistral (40 entries) and OpenAI (201 entries), generated from the providers' live deprecation pages plus the AWS Bedrock, Google Vertex AI, and Azure Foundry lifecycle pages, feed data generated 2026-09-21<!-- /feeds-status -->. Every
|
|
40
40
|
dated entry carries a source URL. Anthropic's "not sooner than" dates for
|
|
41
41
|
active models are included as `tentative` planning floors.
|
|
42
42
|
- **`check.mjs`** - zero-dependency CLI: CI gate, PR diff gate, inventory, CycloneDX
|
|
@@ -315,6 +315,17 @@ Under `--via aws-bedrock`, these floors remain `scheduled` and display "not soon
|
|
|
315
315
|
A distributor's later date gives you more time for the same migration. It is not a reason to
|
|
316
316
|
skip it.
|
|
317
317
|
|
|
318
|
+
The later date is also the last day you can still call the old model, when the
|
|
319
|
+
feed gives it as an exact date. A tentative or earliest floor is "at least until",
|
|
320
|
+
and the old model may answer past it. When a retired or retiring model still
|
|
321
|
+
answers on another channel, `check` appends
|
|
322
|
+
`[still answers via aws-bedrock until 2026-10-14]` to the line, and the bot adds
|
|
323
|
+
a `## Capture window` section to its PRs and issues. If your eval compares the
|
|
324
|
+
replacement's outputs against the old model's, capture that baseline before the
|
|
325
|
+
window closes. model-eol reports the window from the feeds and never runs the
|
|
326
|
+
capture; see [docs/DESIGN_EVAL_BOUNDARY.md](docs/DESIGN_EVAL_BOUNDARY.md) for
|
|
327
|
+
where that line sits and why.
|
|
328
|
+
|
|
318
329
|
## Policy floors
|
|
319
330
|
|
|
320
331
|
A feed entry with no `announced` and no `shutdown` means "nothing scheduled as
|
|
@@ -445,6 +456,8 @@ receives:
|
|
|
445
456
|
- `MODEL_EOL_OLD_ID` and `MODEL_EOL_NEW_ID` for the current migration.
|
|
446
457
|
- `MODEL_EOL_PLAN`, a one-model plan containing the exact changed references.
|
|
447
458
|
- `MODEL_EOL_REPORT`, the required path for a bounded, publishable Markdown receipt.
|
|
459
|
+
- `MODEL_EOL_VIA`, the distributor channel the plan was built for, or empty for the publisher's direct API. Use it to map the publisher's replacement ID to your client's ID on that channel.
|
|
460
|
+
- `MODEL_EOL_EVAL_MODE`, always `evaluate` today. The value `capture` is reserved for a future run on the unpatched checkout against the old ID. The bot does not run it, and the hook refuses any other value.
|
|
448
461
|
|
|
449
462
|
Exit zero plus a regular report file means pass. Any other exit, a timeout, a
|
|
450
463
|
missing report, a tracked workspace change, or checkout drift fails that
|
|
@@ -516,6 +529,12 @@ node scripts/feed-changelog.mjs # local rendering of the h
|
|
|
516
529
|
|
|
517
530
|
A parse failure stops the run. The refresh never writes a guessed feed.
|
|
518
531
|
|
|
532
|
+
Anthropic reads model IDs and aliases from overview pages listed in `https://platform.claude.com/docs/llms.txt`.
|
|
533
|
+
It reads at most 100 unique pages with 30-second deadlines and 8 MiB response limits.
|
|
534
|
+
Only the deprecations page supplies Anthropic dates.
|
|
535
|
+
Offline checks use `anthropic-llms.txt` and `anthropic-model-pages/<slug>.md`; missing pages stop refresh.
|
|
536
|
+
Alias attachments and moves emit notices and appear in semantic diffs.
|
|
537
|
+
|
|
519
538
|
AWS changed its Bedrock lifecycle policy on 2026-09-07.
|
|
520
539
|
The legacy table covers models launched before that date; newer models publish lifecycle dates on individual cards.
|
|
521
540
|
The Bedrock refresh reads both sources and keeps legacy-table records when IDs overlap.
|
package/SPEC.md
CHANGED
|
@@ -72,6 +72,7 @@ available even when it does not publish an exact shutdown date.
|
|
|
72
72
|
Bedrock model-card floors are tentative distribution dates (`date_precision: "tentative"`) without `announced`.
|
|
73
73
|
|
|
74
74
|
Azure maps GA/Preview/Legacy to `active`, Deprecated to `legacy`, and Retired to `retired`; Azure Legacy permits new deployments.
|
|
75
|
+
Azure OpenAI uses a resolving bare identity for single-row models only when a dated snapshot candidate is absent.
|
|
75
76
|
|
|
76
77
|
A model may contain at most one distribution for each `via`. Duplicate channel
|
|
77
78
|
records are ambiguous and fail runtime semantic validation. Draft-07 can enforce
|
package/bot/bot.mjs
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
stableJson,
|
|
26
26
|
} from './lib/common.mjs'
|
|
27
27
|
import { assertValidPlanDocument } from '../lib/validate-document.mjs'
|
|
28
|
+
import { captureWindowFor, lifecycleFor } from '../lib/feeds.mjs'
|
|
28
29
|
import { parseCliArgs } from '../lib/cli.mjs'
|
|
29
30
|
import { loadConfig } from './lib/config.mjs'
|
|
30
31
|
import { downloadFeeds } from './lib/feeds.mjs'
|
|
@@ -363,11 +364,21 @@ const buildModelGroups = (plan, config, root, records) => {
|
|
|
363
364
|
}
|
|
364
365
|
for (const group of groups.values()) {
|
|
365
366
|
group.items.sort((a, b) => `${a.file}:${a.line}:${a.occurrence}`.localeCompare(`${b.file}:${b.line}:${b.occurrence}`))
|
|
366
|
-
group.feedDigest =
|
|
367
|
+
group.feedDigest = groupDigest(group.items, group.context?.entry)
|
|
367
368
|
}
|
|
368
369
|
return [...groups.values()].sort((a, b) => `${a.publisher}/${a.id}`.localeCompare(`${b.publisher}/${b.id}`))
|
|
369
370
|
}
|
|
370
371
|
|
|
372
|
+
// the capture section reads clocks outside the plan items, so they join the digest that gates body updates
|
|
373
|
+
const clockRows = entry => entry
|
|
374
|
+
? {
|
|
375
|
+
shutdown: entry.shutdown ?? null,
|
|
376
|
+
date_precision: entry.date_precision ?? null,
|
|
377
|
+
distributions: itemDigest((entry.distributions ?? []).map(row => ({ via: row.via, shutdown: row.shutdown ?? null, status: row.status ?? null, date_precision: row.date_precision ?? null }))),
|
|
378
|
+
}
|
|
379
|
+
: null
|
|
380
|
+
const groupDigest = (items, entry) => sha256(stableJson({ items: itemDigest(items), clocks: clockRows(entry) }))
|
|
381
|
+
|
|
371
382
|
const buildIssueGroups = (plan, config, root, records) => {
|
|
372
383
|
const ignoredIds = ignoredModelIds(plan, config)
|
|
373
384
|
const groups = new Map()
|
|
@@ -398,7 +409,7 @@ const buildIssueGroups = (plan, config, root, records) => {
|
|
|
398
409
|
}
|
|
399
410
|
for (const group of groups.values()) {
|
|
400
411
|
group.issues.sort((a, b) => `${a.file}:${a.line}:${a.reason}`.localeCompare(`${b.file}:${b.line}:${b.reason}`))
|
|
401
|
-
group.feedDigest =
|
|
412
|
+
group.feedDigest = groupDigest(group.issues, group.context?.entry)
|
|
402
413
|
}
|
|
403
414
|
return [...groups.values()].sort((a, b) => `${a.publisher}/${a.subject}/${a.shutdown ?? ''}`.localeCompare(`${b.publisher}/${b.subject}/${b.shutdown ?? ''}`))
|
|
404
415
|
}
|
|
@@ -484,6 +495,43 @@ const replacementSection = (item, now) => [
|
|
|
484
495
|
: []),
|
|
485
496
|
]
|
|
486
497
|
|
|
498
|
+
const captureWindow = (group, now) => {
|
|
499
|
+
const entry = group.context?.entry
|
|
500
|
+
if (!entry) return null
|
|
501
|
+
const lifecycle = lifecycleFor(entry, {
|
|
502
|
+
days: group.items?.[0]?.threshold_days ?? group.issues?.[0]?.threshold_days ?? 0,
|
|
503
|
+
via: group.via ?? null,
|
|
504
|
+
today: now,
|
|
505
|
+
})
|
|
506
|
+
return captureWindowFor(entry, lifecycle, { today: now })
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// the first date on which the capture section changes, so a body can be refreshed when the digest cannot see it
|
|
510
|
+
const captureExpiry = capture => capture
|
|
511
|
+
? [capture.until, ...capture.alternatives.map(alternative => alternative.until)].filter(Boolean).sort()[0] ?? null
|
|
512
|
+
: null
|
|
513
|
+
|
|
514
|
+
const captureExpired = (metadata, now) => typeof metadata.capture_expires === 'string' && metadata.capture_expires <= now.toISOString().slice(0, 10)
|
|
515
|
+
|
|
516
|
+
const captureSection = (group, now) => {
|
|
517
|
+
const capture = captureWindow(group, now)
|
|
518
|
+
if (!capture) return ''
|
|
519
|
+
const clock = capture.via === 'publisher' || capture.via === 'publisher-fallback'
|
|
520
|
+
? markdownText('publisher')
|
|
521
|
+
: markdownCode(capture.via)
|
|
522
|
+
const untilText = window => `${['tentative', 'earliest'].includes(window.date_precision) ? 'at least until' : 'until'} ${markdownText(window.until)}`
|
|
523
|
+
return [
|
|
524
|
+
'## Capture window',
|
|
525
|
+
capture.until !== null
|
|
526
|
+
? `- The old model answers on the ${clock} clock ${untilText(capture)}.`
|
|
527
|
+
: `- The old model no longer answers on the ${clock} clock. No baseline can be captured from it there.`,
|
|
528
|
+
...capture.alternatives.map(alternative => `- It still answers via ${markdownCode(alternative.via)} ${untilText(alternative)}.`),
|
|
529
|
+
capture.until === null && capture.alternatives.length === 0
|
|
530
|
+
? '- The feed lists no dated clock on which the old model still answers, so model-eol cannot state a capture window. model-eol does not run captures.'
|
|
531
|
+
: '- Capture a baseline from the old model before the window closes if your eval compares outputs. model-eol does not run captures.',
|
|
532
|
+
].join('\n')
|
|
533
|
+
}
|
|
534
|
+
|
|
487
535
|
export const buildPullBody = ({ group, headSha, baseSha = null, now = new Date(), tokenKind = null, evalResult = null, evalConfigHash = null }) => {
|
|
488
536
|
const item = group.items[0]
|
|
489
537
|
const announced = markdownText(group.context?.announced ?? 'not specified')
|
|
@@ -500,6 +548,7 @@ export const buildPullBody = ({ group, headSha, baseSha = null, now = new Date()
|
|
|
500
548
|
base_sha: baseSha,
|
|
501
549
|
head_sha: headSha,
|
|
502
550
|
feed_digest: group.feedDigest,
|
|
551
|
+
capture_expires: captureExpiry(captureWindow(group, now)),
|
|
503
552
|
...(evalConfigHash ? { eval_config_digest: evalConfigHash } : {}),
|
|
504
553
|
}
|
|
505
554
|
const sections = [
|
|
@@ -522,6 +571,8 @@ export const buildPullBody = ({ group, headSha, baseSha = null, now = new Date()
|
|
|
522
571
|
if (group.via) {
|
|
523
572
|
sections.push('', '## Distributor clock', `This migration uses the ${markdownCode(group.via)} distributor clock; the shutdown date above is the date for that channel.`)
|
|
524
573
|
}
|
|
574
|
+
const capture = captureSection(group, now)
|
|
575
|
+
if (capture) sections.push('', capture)
|
|
525
576
|
const evaluation = evalSection(evalResult)
|
|
526
577
|
if (evaluation) sections.push('', evaluation)
|
|
527
578
|
sections.push(
|
|
@@ -547,6 +598,7 @@ export const buildIssueBody = ({ group, now = new Date() }) => {
|
|
|
547
598
|
replacement_note: issue.replacement_note,
|
|
548
599
|
head_sha: null,
|
|
549
600
|
feed_digest: group.feedDigest,
|
|
601
|
+
capture_expires: captureExpiry(captureWindow(group, now)),
|
|
550
602
|
...(group.channel ? { channel: group.channel } : {}),
|
|
551
603
|
}
|
|
552
604
|
const evidence = group.issues
|
|
@@ -580,6 +632,8 @@ export const buildIssueBody = ({ group, now = new Date() }) => {
|
|
|
580
632
|
'## Feed notes',
|
|
581
633
|
notesSection(group),
|
|
582
634
|
]
|
|
635
|
+
const capture = captureSection(group, now)
|
|
636
|
+
if (capture) sections.push('', capture)
|
|
583
637
|
const evaluation = evalSection(group.evalResult)
|
|
584
638
|
if (evaluation) sections.push('', evaluation)
|
|
585
639
|
return sections.join('\n')
|
|
@@ -841,6 +895,8 @@ export const evaluatePlan = async ({
|
|
|
841
895
|
cwd: clone,
|
|
842
896
|
oldId: group.id,
|
|
843
897
|
newId: group.items[0].replacement,
|
|
898
|
+
via: group.via ?? null,
|
|
899
|
+
mode: 'evaluate',
|
|
844
900
|
planPath: selectedPlanPath,
|
|
845
901
|
reportPath,
|
|
846
902
|
})
|
|
@@ -1090,7 +1146,7 @@ const processModel = async ({ api, pulls, issueRecords, group, source, base, bas
|
|
|
1090
1146
|
if (externalEval && externalEval.status !== 'pass') {
|
|
1091
1147
|
return processEvalFailure({ api, issueRecords, group, evalResult: externalEval, root, now, issuesEnabled: config.issues.enabled, open })
|
|
1092
1148
|
}
|
|
1093
|
-
if (open.metadata.feed_digest === currentDigest && open.metadata.base_sha === baseHead && (!evalConfigHash || open.metadata.eval_config_digest === evalConfigHash)) {
|
|
1149
|
+
if (open.metadata.feed_digest === currentDigest && open.metadata.base_sha === baseHead && (!evalConfigHash || open.metadata.eval_config_digest === evalConfigHash) && !captureExpired(open.metadata, now)) {
|
|
1094
1150
|
return decision(group, 'skip-unchanged', { number: open.item.number })
|
|
1095
1151
|
}
|
|
1096
1152
|
let patch
|
|
@@ -1250,7 +1306,7 @@ const processIssue = async ({ api, issues, group, now }) => {
|
|
|
1250
1306
|
const open = matches.find(record => isOpen(record.item))
|
|
1251
1307
|
const body = buildIssueBody({ group, now })
|
|
1252
1308
|
if (open) {
|
|
1253
|
-
if (open.metadata.feed_digest === group.feedDigest) return decision(group, 'skip-unchanged', { number: open.item.number, body })
|
|
1309
|
+
if (open.metadata.feed_digest === group.feedDigest && !captureExpired(open.metadata, now)) return decision(group, 'skip-unchanged', { number: open.item.number, body })
|
|
1254
1310
|
await api.updateIssue(open.item.number, { title: issueTitle(group), body })
|
|
1255
1311
|
return decision(group, 'update', { number: open.item.number, body })
|
|
1256
1312
|
}
|
package/bot/lib/common.mjs
CHANGED
|
@@ -16,7 +16,10 @@ const stableValue = value => {
|
|
|
16
16
|
export const stableJson = value => JSON.stringify(stableValue(value))
|
|
17
17
|
|
|
18
18
|
export const sortedJsonDigest = values => {
|
|
19
|
-
const sorted = values.slice().sort((a, b) =>
|
|
19
|
+
const sorted = values.slice().sort((a, b) => {
|
|
20
|
+
const [left, right] = [stableJson(a), stableJson(b)]
|
|
21
|
+
return left < right ? -1 : left > right ? 1 : 0
|
|
22
|
+
})
|
|
20
23
|
return sha256(stableJson(sorted))
|
|
21
24
|
}
|
|
22
25
|
|
|
@@ -67,6 +70,7 @@ export const parseMetadata = body => {
|
|
|
67
70
|
if (metadata.replacement !== undefined && metadata.replacement !== null && typeof metadata.replacement !== 'string') return null
|
|
68
71
|
if (metadata.replacement_options !== undefined && (!Array.isArray(metadata.replacement_options) || metadata.replacement_options.some(option => typeof option !== 'string'))) return null
|
|
69
72
|
if (metadata.replacement_note !== undefined && metadata.replacement_note !== null && typeof metadata.replacement_note !== 'string') return null
|
|
73
|
+
if (metadata.capture_expires !== undefined && metadata.capture_expires !== null && typeof metadata.capture_expires !== 'string') return null
|
|
70
74
|
if (metadata.base_sha !== undefined && metadata.base_sha !== null && (typeof metadata.base_sha !== 'string' || !/^[0-9a-f]{40,64}$/.test(metadata.base_sha))) return null
|
|
71
75
|
if (metadata.stale_closed !== undefined && metadata.stale_closed !== true) return null
|
|
72
76
|
if (typeof metadata.feed_digest !== 'string' || !metadata.feed_digest) return null
|
|
@@ -111,7 +115,11 @@ export const markdownText = value => String(value ?? '')
|
|
|
111
115
|
.map(line => line.replace(/^(\s*)([-+>]\s|\d+\.\s)/, '$1- '))
|
|
112
116
|
.join('\n')
|
|
113
117
|
|
|
114
|
-
|
|
118
|
+
// code spans show entities literally, so drop backticks and line breaks instead of escaping
|
|
119
|
+
export const markdownCode = value => {
|
|
120
|
+
const text = String(value ?? '').replace(/[\r\n]+/g, ' ').replaceAll('`', '')
|
|
121
|
+
return `\`${text === '' ? ' ' : text}\``
|
|
122
|
+
}
|
|
115
123
|
|
|
116
124
|
export const markdownLink = (label, value) => {
|
|
117
125
|
const text = String(value ?? '')
|
package/bot/lib/eval.mjs
CHANGED
|
@@ -50,7 +50,8 @@ export const readReportCapped = (file, limit) => {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export const runEvalHook = ({ command, timeoutMs, maxReportBytes, passEnv = [], cwd, oldId, newId, planPath, reportPath }) => {
|
|
53
|
+
export const runEvalHook = ({ command, timeoutMs, maxReportBytes, passEnv = [], cwd, oldId, newId, planPath, reportPath, via = null, mode = 'evaluate' }) => {
|
|
54
|
+
if (mode !== 'evaluate') throw new Error(`unsupported eval mode: ${mode}`)
|
|
54
55
|
if (fs.existsSync(reportPath)) fs.rmSync(reportPath, { force: true })
|
|
55
56
|
const env = {}
|
|
56
57
|
for (const key of ['PATH', 'HOME', 'TMPDIR', 'LANG', 'USER', 'SHELL']) {
|
|
@@ -63,6 +64,8 @@ export const runEvalHook = ({ command, timeoutMs, maxReportBytes, passEnv = [],
|
|
|
63
64
|
env.MODEL_EOL_NEW_ID = newId
|
|
64
65
|
env.MODEL_EOL_PLAN = planPath
|
|
65
66
|
env.MODEL_EOL_REPORT = reportPath
|
|
67
|
+
env.MODEL_EOL_VIA = via ?? ''
|
|
68
|
+
env.MODEL_EOL_EVAL_MODE = mode
|
|
66
69
|
|
|
67
70
|
const result = spawnSync(command, {
|
|
68
71
|
cwd,
|
package/check.mjs
CHANGED
|
@@ -406,7 +406,8 @@ if (command === 'plan') {
|
|
|
406
406
|
|
|
407
407
|
if (command === 'check') {
|
|
408
408
|
if (AS_JSON) {
|
|
409
|
-
|
|
409
|
+
// capture stays out of the 0.1 document until the contract grows; the human line and the bot carry it
|
|
410
|
+
console.log(JSON.stringify({ schema: 'model-eol/check@0.1', threshold_days: DAYS, distributor: VIA, scope: SCOPE, scan_notes: scan.notes, findings: changedFindings.map(({ capture, ...finding }) => finding) }, null, 2))
|
|
410
411
|
} else {
|
|
411
412
|
console.log(formatCheck({ findings: changedFindings, bad, scannedFiles: scan.files.length, days: DAYS, scope: SCOPE }))
|
|
412
413
|
}
|
package/feeds/anthropic.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"spec": "model-eol/0.1",
|
|
3
3
|
"publisher": "anthropic",
|
|
4
|
-
"generated": "2026-09-
|
|
4
|
+
"generated": "2026-09-21T15:02:11.423Z",
|
|
5
5
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
6
6
|
"policy": {
|
|
7
7
|
"min_notice_days": 60,
|
|
@@ -33,9 +33,6 @@
|
|
|
33
33
|
"claude-3-5-haiku"
|
|
34
34
|
],
|
|
35
35
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
36
|
-
"announced": "2025-12-19",
|
|
37
|
-
"shutdown": "2026-02-19",
|
|
38
|
-
"replacement": "claude-haiku-4-5-20251001",
|
|
39
36
|
"distributions": [
|
|
40
37
|
{
|
|
41
38
|
"via": "aws-bedrock",
|
|
@@ -43,7 +40,10 @@
|
|
|
43
40
|
"status": "active",
|
|
44
41
|
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-3-5-haiku.html"
|
|
45
42
|
}
|
|
46
|
-
]
|
|
43
|
+
],
|
|
44
|
+
"announced": "2025-12-19",
|
|
45
|
+
"shutdown": "2026-02-19",
|
|
46
|
+
"replacement": "claude-haiku-4-5-20251001"
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
49
|
"id": "claude-3-haiku-20240307",
|
|
@@ -238,8 +238,6 @@
|
|
|
238
238
|
{
|
|
239
239
|
"id": "claude-opus-5",
|
|
240
240
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
241
|
-
"shutdown": "2027-07-24",
|
|
242
|
-
"date_precision": "tentative",
|
|
243
241
|
"distributions": [
|
|
244
242
|
{
|
|
245
243
|
"via": "azure-ai-foundry",
|
|
@@ -254,13 +252,13 @@
|
|
|
254
252
|
"status": "active",
|
|
255
253
|
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-opus-5.html"
|
|
256
254
|
}
|
|
257
|
-
]
|
|
255
|
+
],
|
|
256
|
+
"shutdown": "2027-07-24",
|
|
257
|
+
"date_precision": "tentative"
|
|
258
258
|
},
|
|
259
259
|
{
|
|
260
260
|
"id": "claude-sonnet-5",
|
|
261
261
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
262
|
-
"shutdown": "2027-06-30",
|
|
263
|
-
"date_precision": "tentative",
|
|
264
262
|
"distributions": [
|
|
265
263
|
{
|
|
266
264
|
"via": "azure-ai-foundry",
|
|
@@ -275,13 +273,13 @@
|
|
|
275
273
|
"status": "active",
|
|
276
274
|
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-sonnet-5.html"
|
|
277
275
|
}
|
|
278
|
-
]
|
|
276
|
+
],
|
|
277
|
+
"shutdown": "2027-06-30",
|
|
278
|
+
"date_precision": "tentative"
|
|
279
279
|
},
|
|
280
280
|
{
|
|
281
281
|
"id": "claude-fable-5",
|
|
282
282
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
283
|
-
"shutdown": "2027-06-09",
|
|
284
|
-
"date_precision": "tentative",
|
|
285
283
|
"distributions": [
|
|
286
284
|
{
|
|
287
285
|
"via": "azure-ai-foundry",
|
|
@@ -296,13 +294,13 @@
|
|
|
296
294
|
"status": "active",
|
|
297
295
|
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-fable-5.html"
|
|
298
296
|
}
|
|
299
|
-
]
|
|
297
|
+
],
|
|
298
|
+
"shutdown": "2027-06-09",
|
|
299
|
+
"date_precision": "tentative"
|
|
300
300
|
},
|
|
301
301
|
{
|
|
302
302
|
"id": "claude-opus-4-8",
|
|
303
303
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
304
|
-
"shutdown": "2027-05-28",
|
|
305
|
-
"date_precision": "tentative",
|
|
306
304
|
"distributions": [
|
|
307
305
|
{
|
|
308
306
|
"via": "azure-ai-foundry",
|
|
@@ -317,13 +315,13 @@
|
|
|
317
315
|
"status": "active",
|
|
318
316
|
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-opus-4-8.html"
|
|
319
317
|
}
|
|
320
|
-
]
|
|
318
|
+
],
|
|
319
|
+
"shutdown": "2027-05-28",
|
|
320
|
+
"date_precision": "tentative"
|
|
321
321
|
},
|
|
322
322
|
{
|
|
323
323
|
"id": "claude-opus-4-7",
|
|
324
324
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
325
|
-
"shutdown": "2027-04-16",
|
|
326
|
-
"date_precision": "tentative",
|
|
327
325
|
"distributions": [
|
|
328
326
|
{
|
|
329
327
|
"via": "azure-ai-foundry",
|
|
@@ -338,13 +336,13 @@
|
|
|
338
336
|
"status": "active",
|
|
339
337
|
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-opus-4-7.html"
|
|
340
338
|
}
|
|
341
|
-
]
|
|
339
|
+
],
|
|
340
|
+
"shutdown": "2027-04-16",
|
|
341
|
+
"date_precision": "tentative"
|
|
342
342
|
},
|
|
343
343
|
{
|
|
344
344
|
"id": "claude-sonnet-4-6",
|
|
345
345
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
346
|
-
"shutdown": "2027-02-17",
|
|
347
|
-
"date_precision": "tentative",
|
|
348
346
|
"distributions": [
|
|
349
347
|
{
|
|
350
348
|
"via": "azure-ai-foundry",
|
|
@@ -359,13 +357,13 @@
|
|
|
359
357
|
"status": "active",
|
|
360
358
|
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-sonnet-4-6.html"
|
|
361
359
|
}
|
|
362
|
-
]
|
|
360
|
+
],
|
|
361
|
+
"shutdown": "2027-02-17",
|
|
362
|
+
"date_precision": "tentative"
|
|
363
363
|
},
|
|
364
364
|
{
|
|
365
365
|
"id": "claude-opus-4-6",
|
|
366
366
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
367
|
-
"shutdown": "2027-02-05",
|
|
368
|
-
"date_precision": "tentative",
|
|
369
367
|
"distributions": [
|
|
370
368
|
{
|
|
371
369
|
"via": "azure-ai-foundry",
|
|
@@ -380,13 +378,13 @@
|
|
|
380
378
|
"status": "active",
|
|
381
379
|
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-opus-4-6.html"
|
|
382
380
|
}
|
|
383
|
-
]
|
|
381
|
+
],
|
|
382
|
+
"shutdown": "2027-02-05",
|
|
383
|
+
"date_precision": "tentative"
|
|
384
384
|
},
|
|
385
385
|
{
|
|
386
386
|
"id": "claude-opus-4-5-20251101",
|
|
387
387
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
388
|
-
"shutdown": "2026-11-24",
|
|
389
|
-
"date_precision": "tentative",
|
|
390
388
|
"distributions": [
|
|
391
389
|
{
|
|
392
390
|
"via": "aws-bedrock",
|
|
@@ -394,14 +392,23 @@
|
|
|
394
392
|
"date_precision": "tentative",
|
|
395
393
|
"status": "active",
|
|
396
394
|
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-opus-4-5.html"
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
"via": "azure-ai-foundry",
|
|
398
|
+
"shutdown": "2026-10-19",
|
|
399
|
+
"status": "active",
|
|
400
|
+
"source": "https://learn.microsoft.com/en-us/azure/foundry/openai/concepts/model-retirement-schedule"
|
|
397
401
|
}
|
|
398
|
-
]
|
|
402
|
+
],
|
|
403
|
+
"aliases": [
|
|
404
|
+
"claude-opus-4-5"
|
|
405
|
+
],
|
|
406
|
+
"shutdown": "2026-11-24",
|
|
407
|
+
"date_precision": "tentative"
|
|
399
408
|
},
|
|
400
409
|
{
|
|
401
410
|
"id": "claude-haiku-4-5-20251001",
|
|
402
411
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
403
|
-
"shutdown": "2026-10-15",
|
|
404
|
-
"date_precision": "tentative",
|
|
405
412
|
"distributions": [
|
|
406
413
|
{
|
|
407
414
|
"via": "aws-bedrock",
|
|
@@ -409,14 +416,23 @@
|
|
|
409
416
|
"date_precision": "tentative",
|
|
410
417
|
"status": "active",
|
|
411
418
|
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-haiku-4-5.html"
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
"via": "azure-ai-foundry",
|
|
422
|
+
"shutdown": "2026-10-19",
|
|
423
|
+
"status": "active",
|
|
424
|
+
"source": "https://learn.microsoft.com/en-us/azure/foundry/openai/concepts/model-retirement-schedule"
|
|
412
425
|
}
|
|
413
|
-
]
|
|
426
|
+
],
|
|
427
|
+
"aliases": [
|
|
428
|
+
"claude-haiku-4-5"
|
|
429
|
+
],
|
|
430
|
+
"shutdown": "2026-10-15",
|
|
431
|
+
"date_precision": "tentative"
|
|
414
432
|
},
|
|
415
433
|
{
|
|
416
434
|
"id": "claude-sonnet-4-5-20250929",
|
|
417
435
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
418
|
-
"shutdown": "2026-09-29",
|
|
419
|
-
"date_precision": "tentative",
|
|
420
436
|
"distributions": [
|
|
421
437
|
{
|
|
422
438
|
"via": "aws-bedrock",
|
|
@@ -424,14 +440,23 @@
|
|
|
424
440
|
"date_precision": "tentative",
|
|
425
441
|
"status": "active",
|
|
426
442
|
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-sonnet-4-5.html"
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
"via": "azure-ai-foundry",
|
|
446
|
+
"shutdown": "2026-10-19",
|
|
447
|
+
"status": "active",
|
|
448
|
+
"source": "https://learn.microsoft.com/en-us/azure/foundry/openai/concepts/model-retirement-schedule"
|
|
427
449
|
}
|
|
428
|
-
]
|
|
450
|
+
],
|
|
451
|
+
"aliases": [
|
|
452
|
+
"claude-sonnet-4-5"
|
|
453
|
+
],
|
|
454
|
+
"shutdown": "2026-09-29",
|
|
455
|
+
"date_precision": "tentative"
|
|
429
456
|
},
|
|
430
457
|
{
|
|
431
458
|
"id": "claude-fable-5-1",
|
|
432
459
|
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
433
|
-
"shutdown": "2027-09-01",
|
|
434
|
-
"date_precision": "tentative",
|
|
435
460
|
"distributions": [
|
|
436
461
|
{
|
|
437
462
|
"via": "azure-ai-foundry",
|
|
@@ -446,6 +471,56 @@
|
|
|
446
471
|
"status": "active",
|
|
447
472
|
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-fable-5-1.html"
|
|
448
473
|
}
|
|
474
|
+
],
|
|
475
|
+
"shutdown": "2027-09-01",
|
|
476
|
+
"date_precision": "tentative"
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
"id": "claude-mythos-5",
|
|
480
|
+
"distributions": [
|
|
481
|
+
{
|
|
482
|
+
"via": "aws-bedrock",
|
|
483
|
+
"shutdown": "2027-06-09",
|
|
484
|
+
"date_precision": "tentative",
|
|
485
|
+
"status": "active",
|
|
486
|
+
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-mythos-5.html"
|
|
487
|
+
}
|
|
488
|
+
],
|
|
489
|
+
"shutdown": "2027-06-09",
|
|
490
|
+
"date_precision": "tentative",
|
|
491
|
+
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations"
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
"id": "claude-mythos-5-1",
|
|
495
|
+
"distributions": [
|
|
496
|
+
{
|
|
497
|
+
"via": "aws-bedrock",
|
|
498
|
+
"shutdown": "2027-09-01",
|
|
499
|
+
"date_precision": "tentative",
|
|
500
|
+
"status": "active",
|
|
501
|
+
"source": "https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-mythos-5-1.html"
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
"via": "azure-ai-foundry",
|
|
505
|
+
"status": "active",
|
|
506
|
+
"source": "https://learn.microsoft.com/en-us/azure/foundry/openai/concepts/model-retirement-schedule"
|
|
507
|
+
}
|
|
508
|
+
],
|
|
509
|
+
"shutdown": "2027-09-01",
|
|
510
|
+
"date_precision": "tentative",
|
|
511
|
+
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations"
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
"id": "claude-mythos-preview",
|
|
515
|
+
"announced": "2026-06-09",
|
|
516
|
+
"source": "https://platform.claude.com/docs/en/about-claude/model-deprecations",
|
|
517
|
+
"distributions": [
|
|
518
|
+
{
|
|
519
|
+
"via": "azure-ai-foundry",
|
|
520
|
+
"shutdown": "2027-04-02",
|
|
521
|
+
"status": "active",
|
|
522
|
+
"source": "https://learn.microsoft.com/en-us/azure/foundry/openai/concepts/model-retirement-schedule"
|
|
523
|
+
}
|
|
449
524
|
]
|
|
450
525
|
}
|
|
451
526
|
]
|