modelbump 0.1.0__py3-none-any.whl
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.
- modelbump/__init__.py +5 -0
- modelbump/cli.py +154 -0
- modelbump/py.typed +0 -0
- modelbump/registry/__init__.py +27 -0
- modelbump/registry/data/anthropic.yaml +88 -0
- modelbump/registry/data/google.yaml +102 -0
- modelbump/registry/data/openai.yaml +384 -0
- modelbump/registry/loader.py +59 -0
- modelbump/registry/models.py +111 -0
- modelbump/scanner/__init__.py +26 -0
- modelbump/scanner/context.py +384 -0
- modelbump/scanner/files.py +161 -0
- modelbump/scanner/ids.py +95 -0
- modelbump/scanner/report.py +334 -0
- modelbump/scanner/resolve.py +37 -0
- modelbump/scanner/scan.py +91 -0
- modelbump/scanner/severity.py +65 -0
- modelbump-0.1.0.dist-info/METADATA +162 -0
- modelbump-0.1.0.dist-info/RECORD +22 -0
- modelbump-0.1.0.dist-info/WHEEL +4 -0
- modelbump-0.1.0.dist-info/entry_points.txt +3 -0
- modelbump-0.1.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
# Copied from the source page. Scope: models called through text-generation or
|
|
2
|
+
# embedding APIs; audio, realtime, image, video, moderation and fine-tuning
|
|
3
|
+
# entries are left out (see docs/architecture/registry.md).
|
|
4
|
+
# `announced` is the date of the page section; `shutdown` is its shutdown date.
|
|
5
|
+
# `replacement` is what the page recommends TODAY (see ADR 0006).
|
|
6
|
+
# When a model appears in more than one section, the newest section is the
|
|
7
|
+
# current plan and older ones go under `superseded` (see ADR 0007).
|
|
8
|
+
provider: openai
|
|
9
|
+
source_url: https://developers.openai.com/api/docs/deprecations
|
|
10
|
+
retrieved: 2026-10-08
|
|
11
|
+
models:
|
|
12
|
+
- id: gpt-5.3-codex
|
|
13
|
+
announced: 2026-10-01
|
|
14
|
+
shutdown: 2027-04-01
|
|
15
|
+
replacement: gpt-6-sol
|
|
16
|
+
- id: gpt-5.4-nano
|
|
17
|
+
announced: 2026-10-01
|
|
18
|
+
shutdown: 2027-04-01
|
|
19
|
+
replacement: gpt-6-luna
|
|
20
|
+
- id: gpt-5.1
|
|
21
|
+
announced: 2026-10-01
|
|
22
|
+
shutdown: 2027-04-01
|
|
23
|
+
replacement: gpt-6-sol
|
|
24
|
+
- id: gpt-5.4-cyber
|
|
25
|
+
announced: 2026-09-11
|
|
26
|
+
shutdown: 2026-10-01
|
|
27
|
+
notes: "Page recommends the most capable cyber model available to you."
|
|
28
|
+
- id: gpt-5-2025-08-07
|
|
29
|
+
announced: 2026-06-11
|
|
30
|
+
shutdown: 2026-12-11
|
|
31
|
+
replacement: gpt-5.6-sol
|
|
32
|
+
- id: gpt-5-mini-2025-08-07
|
|
33
|
+
announced: 2026-06-11
|
|
34
|
+
shutdown: 2026-12-11
|
|
35
|
+
replacement: gpt-5.6-terra
|
|
36
|
+
- id: gpt-5-nano-2025-08-07
|
|
37
|
+
announced: 2026-06-11
|
|
38
|
+
shutdown: 2026-12-11
|
|
39
|
+
replacement: gpt-5.6-luna
|
|
40
|
+
- id: gpt-5-pro-2025-10-06
|
|
41
|
+
announced: 2026-06-11
|
|
42
|
+
shutdown: 2026-12-11
|
|
43
|
+
replacement: gpt-5.6-sol
|
|
44
|
+
notes: "Replacement uses reasoning.mode pro."
|
|
45
|
+
- id: o3-2025-04-16
|
|
46
|
+
announced: 2026-06-11
|
|
47
|
+
shutdown: 2026-12-11
|
|
48
|
+
replacement: gpt-5.6-sol
|
|
49
|
+
- id: o3-pro-2025-06-10
|
|
50
|
+
announced: 2026-06-11
|
|
51
|
+
shutdown: 2026-12-11
|
|
52
|
+
replacement: gpt-5.6-sol
|
|
53
|
+
notes: "Replacement uses reasoning.mode pro."
|
|
54
|
+
- id: gpt-5.2-chat-latest
|
|
55
|
+
announced: 2026-05-08
|
|
56
|
+
shutdown: 2026-08-10
|
|
57
|
+
replacement: gpt-5.6-sol
|
|
58
|
+
- id: gpt-5.3-chat-latest
|
|
59
|
+
announced: 2026-05-08
|
|
60
|
+
shutdown: 2026-08-10
|
|
61
|
+
replacement: gpt-5.6-sol
|
|
62
|
+
- id: gpt-3.5-turbo-0125
|
|
63
|
+
aliases: [gpt-3.5-turbo]
|
|
64
|
+
announced: 2026-04-22
|
|
65
|
+
shutdown: 2026-10-23
|
|
66
|
+
replacement: gpt-5.6-terra
|
|
67
|
+
- id: gpt-4-0613
|
|
68
|
+
aliases: [gpt-4, gpt-4-0613-completions, gpt-4-completions]
|
|
69
|
+
announced: 2026-04-22
|
|
70
|
+
shutdown: 2026-10-23
|
|
71
|
+
replacement: gpt-5.6-sol
|
|
72
|
+
- id: gpt-4-1106-preview
|
|
73
|
+
announced: 2026-04-22
|
|
74
|
+
shutdown: 2026-10-23
|
|
75
|
+
replacement: gpt-5.6-sol
|
|
76
|
+
notes: "Rescheduled: first set to shut down on 2026-03-26."
|
|
77
|
+
superseded:
|
|
78
|
+
- announced: 2025-09-26
|
|
79
|
+
shutdown: 2026-03-26
|
|
80
|
+
- id: gpt-4-turbo-2024-04-09
|
|
81
|
+
aliases: [gpt-4-turbo, gpt-4-turbo-completions]
|
|
82
|
+
announced: 2026-04-22
|
|
83
|
+
shutdown: 2026-10-23
|
|
84
|
+
replacement: gpt-5.6-sol
|
|
85
|
+
- id: gpt-4.1-nano-2025-04-14
|
|
86
|
+
aliases: [gpt-4.1-nano]
|
|
87
|
+
announced: 2026-04-22
|
|
88
|
+
shutdown: 2026-10-23
|
|
89
|
+
replacement: gpt-5.6-luna
|
|
90
|
+
- id: gpt-4o-2024-05-13
|
|
91
|
+
announced: 2026-04-22
|
|
92
|
+
shutdown: 2026-10-23
|
|
93
|
+
replacement: gpt-5.6-sol
|
|
94
|
+
- id: o1-2024-12-17
|
|
95
|
+
aliases: [o1]
|
|
96
|
+
announced: 2026-04-22
|
|
97
|
+
shutdown: 2026-10-23
|
|
98
|
+
replacement: gpt-5.6-sol
|
|
99
|
+
- id: o1-pro-2025-03-19
|
|
100
|
+
aliases: [o1-pro]
|
|
101
|
+
announced: 2026-04-22
|
|
102
|
+
shutdown: 2026-10-23
|
|
103
|
+
replacement: gpt-5.6-sol
|
|
104
|
+
notes: "Replacement uses reasoning.mode pro."
|
|
105
|
+
- id: o3-mini-2025-01-31
|
|
106
|
+
aliases: [o3-mini]
|
|
107
|
+
announced: 2026-04-22
|
|
108
|
+
shutdown: 2026-10-23
|
|
109
|
+
replacement: gpt-5.6-sol
|
|
110
|
+
- id: o4-mini-2025-04-16
|
|
111
|
+
aliases: [o4-mini]
|
|
112
|
+
announced: 2026-04-22
|
|
113
|
+
shutdown: 2026-10-23
|
|
114
|
+
replacement: gpt-5.6-terra
|
|
115
|
+
- id: computer-use-preview-2025-03-11
|
|
116
|
+
aliases: [computer-use-preview]
|
|
117
|
+
announced: 2026-04-22
|
|
118
|
+
shutdown: 2026-07-23
|
|
119
|
+
replacement: gpt-5.6-terra
|
|
120
|
+
- id: gpt-4o-mini-search-preview-2025-03-11
|
|
121
|
+
announced: 2026-04-22
|
|
122
|
+
shutdown: 2026-07-23
|
|
123
|
+
replacement: gpt-5.6-terra
|
|
124
|
+
- id: gpt-4o-search-preview-2025-03-11
|
|
125
|
+
announced: 2026-04-22
|
|
126
|
+
shutdown: 2026-07-23
|
|
127
|
+
replacement: gpt-5.6-terra
|
|
128
|
+
- id: gpt-5-chat-latest
|
|
129
|
+
announced: 2026-04-22
|
|
130
|
+
shutdown: 2026-07-23
|
|
131
|
+
replacement: gpt-5.6-sol
|
|
132
|
+
- id: gpt-5-codex
|
|
133
|
+
announced: 2026-04-22
|
|
134
|
+
shutdown: 2026-07-23
|
|
135
|
+
replacement: gpt-5.6-sol
|
|
136
|
+
- id: gpt-5.1-chat-latest
|
|
137
|
+
announced: 2026-04-22
|
|
138
|
+
shutdown: 2026-07-23
|
|
139
|
+
replacement: gpt-5.6-sol
|
|
140
|
+
- id: gpt-5.1-codex
|
|
141
|
+
announced: 2026-04-22
|
|
142
|
+
shutdown: 2026-07-23
|
|
143
|
+
replacement: gpt-5.6-sol
|
|
144
|
+
- id: gpt-5.1-codex-max
|
|
145
|
+
announced: 2026-04-22
|
|
146
|
+
shutdown: 2026-07-23
|
|
147
|
+
replacement: gpt-5.6-sol
|
|
148
|
+
- id: gpt-5.1-codex-mini
|
|
149
|
+
announced: 2026-04-22
|
|
150
|
+
shutdown: 2026-07-23
|
|
151
|
+
replacement: gpt-5.6-terra
|
|
152
|
+
- id: o3-deep-research-2025-06-26
|
|
153
|
+
aliases: [o3-deep-research]
|
|
154
|
+
announced: 2026-04-22
|
|
155
|
+
shutdown: 2026-07-23
|
|
156
|
+
replacement: gpt-5.6-sol
|
|
157
|
+
- id: o4-mini-deep-research-2025-06-26
|
|
158
|
+
aliases: [o4-mini-deep-research]
|
|
159
|
+
announced: 2026-04-22
|
|
160
|
+
shutdown: 2026-07-23
|
|
161
|
+
replacement: gpt-5.6-sol
|
|
162
|
+
- id: gpt-5.2-codex
|
|
163
|
+
announced: 2026-04-22
|
|
164
|
+
shutdown: 2026-07-23
|
|
165
|
+
replacement: gpt-5.6-sol
|
|
166
|
+
- id: chatgpt-4o-latest
|
|
167
|
+
announced: 2025-11-18
|
|
168
|
+
shutdown: 2026-02-17
|
|
169
|
+
replacement: gpt-5.1-chat-latest
|
|
170
|
+
- id: codex-mini-latest
|
|
171
|
+
announced: 2025-11-17
|
|
172
|
+
shutdown: 2026-02-12
|
|
173
|
+
replacement: gpt-5-codex-mini
|
|
174
|
+
- id: gpt-3.5-turbo-instruct
|
|
175
|
+
announced: 2025-09-26
|
|
176
|
+
shutdown: 2026-09-28
|
|
177
|
+
replacement: gpt-5.6-terra
|
|
178
|
+
- id: babbage-002
|
|
179
|
+
announced: 2025-09-26
|
|
180
|
+
shutdown: 2026-09-28
|
|
181
|
+
replacement: gpt-5.6-terra
|
|
182
|
+
- id: davinci-002
|
|
183
|
+
announced: 2025-09-26
|
|
184
|
+
shutdown: 2026-09-28
|
|
185
|
+
replacement: gpt-5.6-terra
|
|
186
|
+
- id: gpt-3.5-turbo-1106
|
|
187
|
+
announced: 2025-09-26
|
|
188
|
+
shutdown: 2026-09-28
|
|
189
|
+
replacement: gpt-5.6-terra
|
|
190
|
+
- id: gpt-4-0314
|
|
191
|
+
announced: 2025-09-26
|
|
192
|
+
shutdown: 2026-03-26
|
|
193
|
+
replacement: gpt-5
|
|
194
|
+
notes: "Rescheduled: first announced on 2023-06-13 with shutdown at earliest 2024-06-13. Page recommends gpt-5 or gpt-4.1."
|
|
195
|
+
superseded:
|
|
196
|
+
- announced: 2023-06-13
|
|
197
|
+
shutdown: 2024-06-13
|
|
198
|
+
shutdown_is_earliest: true
|
|
199
|
+
- id: gpt-4-0125-preview
|
|
200
|
+
aliases: [gpt-4-turbo-preview, gpt-4-turbo-preview-completions]
|
|
201
|
+
announced: 2025-09-26
|
|
202
|
+
shutdown: 2026-03-26
|
|
203
|
+
replacement: gpt-5
|
|
204
|
+
notes: "Page recommends gpt-5 or gpt-4.1."
|
|
205
|
+
- id: o1-preview
|
|
206
|
+
announced: 2025-04-28
|
|
207
|
+
shutdown: 2025-07-28
|
|
208
|
+
replacement: o3
|
|
209
|
+
- id: o1-mini
|
|
210
|
+
announced: 2025-04-28
|
|
211
|
+
shutdown: 2025-10-27
|
|
212
|
+
replacement: o4-mini
|
|
213
|
+
- id: gpt-4.5-preview
|
|
214
|
+
announced: 2025-04-14
|
|
215
|
+
shutdown: 2025-07-14
|
|
216
|
+
replacement: gpt-4.1
|
|
217
|
+
- id: gpt-4-32k
|
|
218
|
+
announced: 2024-06-06
|
|
219
|
+
shutdown: 2025-06-06
|
|
220
|
+
replacement: gpt-4o
|
|
221
|
+
- id: gpt-4-32k-0613
|
|
222
|
+
announced: 2024-06-06
|
|
223
|
+
shutdown: 2025-06-06
|
|
224
|
+
replacement: gpt-4o
|
|
225
|
+
- id: gpt-4-32k-0314
|
|
226
|
+
announced: 2024-06-06
|
|
227
|
+
shutdown: 2025-06-06
|
|
228
|
+
replacement: gpt-4o
|
|
229
|
+
notes: "Also listed in the 2023-06-13 section with the same shutdown date."
|
|
230
|
+
superseded:
|
|
231
|
+
- announced: 2023-06-13
|
|
232
|
+
shutdown: 2025-06-06
|
|
233
|
+
- id: gpt-4-vision-preview
|
|
234
|
+
announced: 2024-06-06
|
|
235
|
+
shutdown: 2024-12-06
|
|
236
|
+
replacement: gpt-4o
|
|
237
|
+
- id: gpt-4-1106-vision-preview
|
|
238
|
+
announced: 2024-06-06
|
|
239
|
+
shutdown: 2024-12-06
|
|
240
|
+
replacement: gpt-4o
|
|
241
|
+
- id: gpt-3.5-turbo-0613
|
|
242
|
+
announced: 2023-11-06
|
|
243
|
+
shutdown: 2024-09-13
|
|
244
|
+
replacement: gpt-3.5-turbo
|
|
245
|
+
- id: gpt-3.5-turbo-16k-0613
|
|
246
|
+
announced: 2023-11-06
|
|
247
|
+
shutdown: 2024-09-13
|
|
248
|
+
replacement: gpt-3.5-turbo
|
|
249
|
+
- id: text-ada-001
|
|
250
|
+
announced: 2023-07-06
|
|
251
|
+
shutdown: 2024-01-04
|
|
252
|
+
replacement: gpt-3.5-turbo-instruct
|
|
253
|
+
- id: text-babbage-001
|
|
254
|
+
announced: 2023-07-06
|
|
255
|
+
shutdown: 2024-01-04
|
|
256
|
+
replacement: gpt-3.5-turbo-instruct
|
|
257
|
+
- id: text-curie-001
|
|
258
|
+
announced: 2023-07-06
|
|
259
|
+
shutdown: 2024-01-04
|
|
260
|
+
replacement: gpt-3.5-turbo-instruct
|
|
261
|
+
- id: text-davinci-001
|
|
262
|
+
announced: 2023-07-06
|
|
263
|
+
shutdown: 2024-01-04
|
|
264
|
+
replacement: gpt-3.5-turbo-instruct
|
|
265
|
+
- id: text-davinci-002
|
|
266
|
+
announced: 2023-07-06
|
|
267
|
+
shutdown: 2024-01-04
|
|
268
|
+
replacement: gpt-3.5-turbo-instruct
|
|
269
|
+
- id: text-davinci-003
|
|
270
|
+
announced: 2023-07-06
|
|
271
|
+
shutdown: 2024-01-04
|
|
272
|
+
replacement: gpt-3.5-turbo-instruct
|
|
273
|
+
- id: ada
|
|
274
|
+
announced: 2023-07-06
|
|
275
|
+
shutdown: 2024-01-04
|
|
276
|
+
replacement: babbage-002
|
|
277
|
+
- id: babbage
|
|
278
|
+
announced: 2023-07-06
|
|
279
|
+
shutdown: 2024-01-04
|
|
280
|
+
replacement: babbage-002
|
|
281
|
+
- id: curie
|
|
282
|
+
announced: 2023-07-06
|
|
283
|
+
shutdown: 2024-01-04
|
|
284
|
+
replacement: davinci-002
|
|
285
|
+
- id: davinci
|
|
286
|
+
announced: 2023-07-06
|
|
287
|
+
shutdown: 2024-01-04
|
|
288
|
+
replacement: davinci-002
|
|
289
|
+
- id: code-davinci-002
|
|
290
|
+
announced: 2023-07-06
|
|
291
|
+
shutdown: 2024-01-04
|
|
292
|
+
replacement: gpt-3.5-turbo-instruct
|
|
293
|
+
notes: "Rescheduled: the 2023-03-20 section lists a 2023-03-23 shutdown."
|
|
294
|
+
superseded:
|
|
295
|
+
- announced: 2023-03-20
|
|
296
|
+
shutdown: 2023-03-23
|
|
297
|
+
- id: text-davinci-edit-001
|
|
298
|
+
announced: 2023-07-06
|
|
299
|
+
shutdown: 2024-01-04
|
|
300
|
+
replacement: gpt-4o
|
|
301
|
+
- id: code-davinci-edit-001
|
|
302
|
+
announced: 2023-07-06
|
|
303
|
+
shutdown: 2024-01-04
|
|
304
|
+
replacement: gpt-4o
|
|
305
|
+
- id: text-similarity-ada-001
|
|
306
|
+
announced: 2023-07-06
|
|
307
|
+
shutdown: 2024-01-04
|
|
308
|
+
replacement: text-embedding-3-small
|
|
309
|
+
- id: text-search-ada-doc-001
|
|
310
|
+
announced: 2023-07-06
|
|
311
|
+
shutdown: 2024-01-04
|
|
312
|
+
replacement: text-embedding-3-small
|
|
313
|
+
- id: text-search-ada-query-001
|
|
314
|
+
announced: 2023-07-06
|
|
315
|
+
shutdown: 2024-01-04
|
|
316
|
+
replacement: text-embedding-3-small
|
|
317
|
+
- id: code-search-ada-code-001
|
|
318
|
+
announced: 2023-07-06
|
|
319
|
+
shutdown: 2024-01-04
|
|
320
|
+
replacement: text-embedding-3-small
|
|
321
|
+
- id: code-search-ada-text-001
|
|
322
|
+
announced: 2023-07-06
|
|
323
|
+
shutdown: 2024-01-04
|
|
324
|
+
replacement: text-embedding-3-small
|
|
325
|
+
- id: text-similarity-babbage-001
|
|
326
|
+
announced: 2023-07-06
|
|
327
|
+
shutdown: 2024-01-04
|
|
328
|
+
replacement: text-embedding-3-small
|
|
329
|
+
- id: text-search-babbage-doc-001
|
|
330
|
+
announced: 2023-07-06
|
|
331
|
+
shutdown: 2024-01-04
|
|
332
|
+
replacement: text-embedding-3-small
|
|
333
|
+
- id: text-search-babbage-query-001
|
|
334
|
+
announced: 2023-07-06
|
|
335
|
+
shutdown: 2024-01-04
|
|
336
|
+
replacement: text-embedding-3-small
|
|
337
|
+
- id: code-search-babbage-code-001
|
|
338
|
+
announced: 2023-07-06
|
|
339
|
+
shutdown: 2024-01-04
|
|
340
|
+
replacement: text-embedding-3-small
|
|
341
|
+
- id: code-search-babbage-text-001
|
|
342
|
+
announced: 2023-07-06
|
|
343
|
+
shutdown: 2024-01-04
|
|
344
|
+
replacement: text-embedding-3-small
|
|
345
|
+
- id: text-similarity-curie-001
|
|
346
|
+
announced: 2023-07-06
|
|
347
|
+
shutdown: 2024-01-04
|
|
348
|
+
replacement: text-embedding-3-small
|
|
349
|
+
- id: text-search-curie-doc-001
|
|
350
|
+
announced: 2023-07-06
|
|
351
|
+
shutdown: 2024-01-04
|
|
352
|
+
replacement: text-embedding-3-small
|
|
353
|
+
- id: text-search-curie-query-001
|
|
354
|
+
announced: 2023-07-06
|
|
355
|
+
shutdown: 2024-01-04
|
|
356
|
+
replacement: text-embedding-3-small
|
|
357
|
+
- id: text-similarity-davinci-001
|
|
358
|
+
announced: 2023-07-06
|
|
359
|
+
shutdown: 2024-01-04
|
|
360
|
+
replacement: text-embedding-3-small
|
|
361
|
+
- id: text-search-davinci-doc-001
|
|
362
|
+
announced: 2023-07-06
|
|
363
|
+
shutdown: 2024-01-04
|
|
364
|
+
replacement: text-embedding-3-small
|
|
365
|
+
- id: text-search-davinci-query-001
|
|
366
|
+
announced: 2023-07-06
|
|
367
|
+
shutdown: 2024-01-04
|
|
368
|
+
replacement: text-embedding-3-small
|
|
369
|
+
- id: gpt-3.5-turbo-0301
|
|
370
|
+
announced: 2023-06-13
|
|
371
|
+
shutdown: 2024-09-13
|
|
372
|
+
replacement: gpt-3.5-turbo
|
|
373
|
+
- id: code-davinci-001
|
|
374
|
+
announced: 2023-03-20
|
|
375
|
+
shutdown: 2023-03-23
|
|
376
|
+
replacement: gpt-4o
|
|
377
|
+
- id: code-cushman-002
|
|
378
|
+
announced: 2023-03-20
|
|
379
|
+
shutdown: 2023-03-23
|
|
380
|
+
replacement: gpt-4o
|
|
381
|
+
- id: code-cushman-001
|
|
382
|
+
announced: 2023-03-20
|
|
383
|
+
shutdown: 2023-03-23
|
|
384
|
+
replacement: gpt-4o
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Load the retirement data files and look models up by ID."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterable, Iterator
|
|
4
|
+
from importlib.resources import files
|
|
5
|
+
from importlib.resources.abc import Traversable
|
|
6
|
+
|
|
7
|
+
import yaml
|
|
8
|
+
|
|
9
|
+
from modelbump.registry.models import Provider, ProviderFile, RetiredModel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DuplicateModelError(ValueError):
|
|
13
|
+
"""Raised when the same model ID appears in more than one entry."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_provider_file(path: Traversable) -> ProviderFile:
|
|
17
|
+
"""Read and validate one YAML data file."""
|
|
18
|
+
data = yaml.safe_load(path.read_text(encoding="utf-8"))
|
|
19
|
+
return ProviderFile.model_validate(data)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Registry:
|
|
23
|
+
"""All known retirements, indexed by every model ID and alias."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, sources: Iterable[ProviderFile]) -> None:
|
|
26
|
+
self._sources = tuple(sources)
|
|
27
|
+
self._by_id: dict[str, tuple[Provider, RetiredModel]] = {}
|
|
28
|
+
for source in self._sources:
|
|
29
|
+
for model in source.models:
|
|
30
|
+
for model_id in model.all_ids():
|
|
31
|
+
if model_id in self._by_id:
|
|
32
|
+
raise DuplicateModelError(f"{model_id} appears more than once")
|
|
33
|
+
self._by_id[model_id] = (source.provider, model)
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def sources(self) -> tuple[ProviderFile, ...]:
|
|
37
|
+
"""The data files this registry was built from."""
|
|
38
|
+
return self._sources
|
|
39
|
+
|
|
40
|
+
def get(self, model_id: str) -> tuple[Provider, RetiredModel] | None:
|
|
41
|
+
"""Return the provider and entry for ``model_id``, or None if unknown."""
|
|
42
|
+
return self._by_id.get(model_id)
|
|
43
|
+
|
|
44
|
+
def __iter__(self) -> Iterator[tuple[Provider, RetiredModel]]:
|
|
45
|
+
for source in self._sources:
|
|
46
|
+
for model in source.models:
|
|
47
|
+
yield source.provider, model
|
|
48
|
+
|
|
49
|
+
def __len__(self) -> int:
|
|
50
|
+
return sum(len(source.models) for source in self._sources)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def load_registry() -> Registry:
|
|
54
|
+
"""Load every data file shipped inside the package."""
|
|
55
|
+
data_dir = files("modelbump.registry") / "data"
|
|
56
|
+
paths = sorted(
|
|
57
|
+
(p for p in data_dir.iterdir() if p.name.endswith(".yaml")), key=lambda p: p.name
|
|
58
|
+
)
|
|
59
|
+
return Registry(load_provider_file(p) for p in paths)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""Data model for the retirement registry.
|
|
2
|
+
|
|
3
|
+
Every field is checked when a data file is loaded, so a typo in a YAML file
|
|
4
|
+
fails the tests instead of silently producing wrong warnings later.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from datetime import date
|
|
8
|
+
from enum import StrEnum
|
|
9
|
+
from typing import Self
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel, ConfigDict, Field, HttpUrl, model_validator
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Provider(StrEnum):
|
|
15
|
+
"""LLM providers whose retirements we track."""
|
|
16
|
+
|
|
17
|
+
ANTHROPIC = "anthropic"
|
|
18
|
+
GOOGLE = "google"
|
|
19
|
+
OPENAI = "openai"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Status(StrEnum):
|
|
23
|
+
"""Where a model is in its life cycle on a given day."""
|
|
24
|
+
|
|
25
|
+
ACTIVE = "active"
|
|
26
|
+
DEPRECATED = "deprecated"
|
|
27
|
+
RETIRED = "retired"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class EarlierPlan(BaseModel):
|
|
31
|
+
"""A retirement plan the provider announced and later replaced."""
|
|
32
|
+
|
|
33
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
34
|
+
|
|
35
|
+
announced: date | None = None
|
|
36
|
+
shutdown: date
|
|
37
|
+
shutdown_is_earliest: bool = False
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class RetiredModel(BaseModel):
|
|
41
|
+
"""One model version that a provider has announced it will shut down."""
|
|
42
|
+
|
|
43
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
44
|
+
|
|
45
|
+
id: str = Field(min_length=1, description="Model ID exactly as used in API calls.")
|
|
46
|
+
aliases: tuple[str, ...] = Field(
|
|
47
|
+
default=(), description="Other IDs that point to this same model."
|
|
48
|
+
)
|
|
49
|
+
announced: date | None = Field(
|
|
50
|
+
default=None, description="Day the provider announced the deprecation."
|
|
51
|
+
)
|
|
52
|
+
shutdown: date = Field(description="Day API calls to this model stop working.")
|
|
53
|
+
shutdown_is_earliest: bool = Field(
|
|
54
|
+
default=False,
|
|
55
|
+
description="True when the source only promises the shutdown no sooner than this day.",
|
|
56
|
+
)
|
|
57
|
+
replacement: str | None = Field(
|
|
58
|
+
default=None,
|
|
59
|
+
description="Replacement the source page recommended on the day we retrieved it.",
|
|
60
|
+
)
|
|
61
|
+
superseded: tuple[EarlierPlan, ...] = Field(
|
|
62
|
+
default=(), description="Earlier retirement plans for this model, oldest first."
|
|
63
|
+
)
|
|
64
|
+
notes: str | None = None
|
|
65
|
+
|
|
66
|
+
@model_validator(mode="after")
|
|
67
|
+
def _check_consistency(self) -> Self:
|
|
68
|
+
if self.announced is not None and self.shutdown < self.announced:
|
|
69
|
+
raise ValueError(f"{self.id}: shutdown {self.shutdown} is before announced")
|
|
70
|
+
ids = self.all_ids()
|
|
71
|
+
if len(set(ids)) != len(ids):
|
|
72
|
+
raise ValueError(f"{self.id}: an alias repeats the id or another alias")
|
|
73
|
+
if self.replacement in ids:
|
|
74
|
+
raise ValueError(f"{self.id}: replacement cannot be the model itself")
|
|
75
|
+
for plan in self.superseded:
|
|
76
|
+
if (
|
|
77
|
+
plan.announced is not None
|
|
78
|
+
and self.announced is not None
|
|
79
|
+
and plan.announced >= self.announced
|
|
80
|
+
):
|
|
81
|
+
raise ValueError(
|
|
82
|
+
f"{self.id}: a superseded plan must be announced before the current one"
|
|
83
|
+
)
|
|
84
|
+
return self
|
|
85
|
+
|
|
86
|
+
def all_ids(self) -> tuple[str, ...]:
|
|
87
|
+
"""Return the main ID followed by every alias."""
|
|
88
|
+
return (self.id, *self.aliases)
|
|
89
|
+
|
|
90
|
+
def status_on(self, day: date) -> Status:
|
|
91
|
+
"""Return the model's status on ``day``, using the current plan.
|
|
92
|
+
|
|
93
|
+
A model is retired from its shutdown day onwards, and deprecated from
|
|
94
|
+
the announcement day until then.
|
|
95
|
+
"""
|
|
96
|
+
if day >= self.shutdown:
|
|
97
|
+
return Status.RETIRED
|
|
98
|
+
if self.announced is not None and day >= self.announced:
|
|
99
|
+
return Status.DEPRECATED
|
|
100
|
+
return Status.ACTIVE
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class ProviderFile(BaseModel):
|
|
104
|
+
"""The contents of one ``data/<provider>.yaml`` file."""
|
|
105
|
+
|
|
106
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
107
|
+
|
|
108
|
+
provider: Provider
|
|
109
|
+
source_url: HttpUrl = Field(description="Page the data was copied from.")
|
|
110
|
+
retrieved: date = Field(description="Day we last checked the data against the source.")
|
|
111
|
+
models: tuple[RetiredModel, ...] = Field(min_length=1)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Scanner: find the LLM model IDs a repository depends on (ADR 0023)."""
|
|
2
|
+
|
|
3
|
+
from modelbump.scanner.context import Context, Place, places
|
|
4
|
+
from modelbump.scanner.files import iter_source_files, read_source
|
|
5
|
+
from modelbump.scanner.ids import IdMatch, ModelIdFinder
|
|
6
|
+
from modelbump.scanner.resolve import resolve
|
|
7
|
+
from modelbump.scanner.scan import Finding, ScanResult, scan_path
|
|
8
|
+
from modelbump.scanner.severity import DEFAULT_SOON_DAYS, Assessment, Severity, assess
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"DEFAULT_SOON_DAYS",
|
|
12
|
+
"Assessment",
|
|
13
|
+
"Context",
|
|
14
|
+
"Finding",
|
|
15
|
+
"IdMatch",
|
|
16
|
+
"ModelIdFinder",
|
|
17
|
+
"Place",
|
|
18
|
+
"ScanResult",
|
|
19
|
+
"Severity",
|
|
20
|
+
"assess",
|
|
21
|
+
"iter_source_files",
|
|
22
|
+
"places",
|
|
23
|
+
"read_source",
|
|
24
|
+
"resolve",
|
|
25
|
+
"scan_path",
|
|
26
|
+
]
|