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
modelbump/__init__.py
ADDED
modelbump/cli.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Command-line interface for ModelBump."""
|
|
2
|
+
|
|
3
|
+
from datetime import date, datetime
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from modelbump import __version__
|
|
10
|
+
from modelbump.registry import Status, load_registry
|
|
11
|
+
from modelbump.scanner import DEFAULT_SOON_DAYS, scan_path
|
|
12
|
+
from modelbump.scanner.report import (
|
|
13
|
+
RENDERERS,
|
|
14
|
+
OutputFormat,
|
|
15
|
+
build_report,
|
|
16
|
+
failure_line,
|
|
17
|
+
summary_line,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
app = typer.Typer(
|
|
21
|
+
name="modelbump",
|
|
22
|
+
help="Dependabot for LLM models.",
|
|
23
|
+
no_args_is_help=True,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _version_callback(value: bool) -> None:
|
|
28
|
+
if value:
|
|
29
|
+
typer.echo(f"modelbump {__version__}")
|
|
30
|
+
raise typer.Exit()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@app.callback()
|
|
34
|
+
def main(
|
|
35
|
+
version: Annotated[
|
|
36
|
+
bool,
|
|
37
|
+
typer.Option(
|
|
38
|
+
"--version",
|
|
39
|
+
"-V",
|
|
40
|
+
help="Show the version and exit.",
|
|
41
|
+
callback=_version_callback,
|
|
42
|
+
is_eager=True,
|
|
43
|
+
),
|
|
44
|
+
] = False,
|
|
45
|
+
) -> None:
|
|
46
|
+
"""Dependabot for LLM models."""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@app.command()
|
|
50
|
+
def scan(
|
|
51
|
+
path: Annotated[
|
|
52
|
+
Path,
|
|
53
|
+
typer.Argument(help="Folder or file to scan.", exists=True, resolve_path=True),
|
|
54
|
+
] = Path("."),
|
|
55
|
+
soon_days: Annotated[
|
|
56
|
+
int,
|
|
57
|
+
typer.Option(
|
|
58
|
+
min=0, help="Mark a model RETIRING_SOON when it shuts down within this many days."
|
|
59
|
+
),
|
|
60
|
+
] = DEFAULT_SOON_DAYS,
|
|
61
|
+
fail_within: Annotated[
|
|
62
|
+
int | None,
|
|
63
|
+
typer.Option(
|
|
64
|
+
min=0,
|
|
65
|
+
help="Exit with code 1 if a model is retired or shuts down within this many days.",
|
|
66
|
+
),
|
|
67
|
+
] = None,
|
|
68
|
+
today: Annotated[
|
|
69
|
+
datetime | None,
|
|
70
|
+
typer.Option(
|
|
71
|
+
formats=["%Y-%m-%d"],
|
|
72
|
+
help="Check as if today were this day (YYYY-MM-DD), to replay the past.",
|
|
73
|
+
),
|
|
74
|
+
] = None,
|
|
75
|
+
output_format: Annotated[
|
|
76
|
+
OutputFormat,
|
|
77
|
+
typer.Option("--format", help="Report format: text, json or sarif."),
|
|
78
|
+
] = OutputFormat.TEXT,
|
|
79
|
+
exclude: Annotated[
|
|
80
|
+
list[str] | None,
|
|
81
|
+
typer.Option(
|
|
82
|
+
help="Skip paths matching this pattern, e.g. 'tests' or '*.ipynb'. Repeat for more.",
|
|
83
|
+
),
|
|
84
|
+
] = None,
|
|
85
|
+
skip_comments: Annotated[
|
|
86
|
+
bool,
|
|
87
|
+
typer.Option(
|
|
88
|
+
help="Leave out IDs that only describe a model: comments, docstrings, "
|
|
89
|
+
"sentences and price tables.",
|
|
90
|
+
),
|
|
91
|
+
] = False,
|
|
92
|
+
skip_tests: Annotated[
|
|
93
|
+
bool,
|
|
94
|
+
typer.Option(help="Leave out test files and test folders."),
|
|
95
|
+
] = False,
|
|
96
|
+
output: Annotated[
|
|
97
|
+
Path | None,
|
|
98
|
+
typer.Option(help="Write the report to this file instead of the screen.", dir_okay=False),
|
|
99
|
+
] = None,
|
|
100
|
+
) -> None:
|
|
101
|
+
"""Find the LLM model IDs in a repository's code and config, and how urgent each is."""
|
|
102
|
+
registry = load_registry()
|
|
103
|
+
day = today.date() if today is not None else date.today()
|
|
104
|
+
result = scan_path(path, registry, exclude or (), skip_comments, skip_tests)
|
|
105
|
+
report = build_report(result, registry, day, soon_days, fail_within, _root_uri(path))
|
|
106
|
+
rendered = RENDERERS[output_format](report)
|
|
107
|
+
if output is None:
|
|
108
|
+
typer.echo(rendered, nl=False)
|
|
109
|
+
else:
|
|
110
|
+
output.write_text(rendered, encoding="utf-8")
|
|
111
|
+
typer.echo(f"Wrote {output_format.value} report to {output}.")
|
|
112
|
+
typer.echo(summary_line(report))
|
|
113
|
+
failure = failure_line(report)
|
|
114
|
+
if failure is not None:
|
|
115
|
+
if output is not None or output_format is not OutputFormat.TEXT:
|
|
116
|
+
# Keep the screen output a valid JSON or SARIF document.
|
|
117
|
+
typer.echo(failure, err=True)
|
|
118
|
+
raise typer.Exit(code=1)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _root_uri(path: Path) -> str:
|
|
122
|
+
"""The scan root relative to the working directory, for SARIF paths."""
|
|
123
|
+
base = path.parent if path.is_file() else path
|
|
124
|
+
try:
|
|
125
|
+
relative = base.relative_to(Path.cwd()).as_posix()
|
|
126
|
+
except ValueError:
|
|
127
|
+
return ""
|
|
128
|
+
return "" if relative == "." else relative + "/"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@app.command()
|
|
132
|
+
def check(
|
|
133
|
+
model_id: Annotated[str, typer.Argument(help="Model ID, e.g. claude-3-haiku-20240307.")],
|
|
134
|
+
) -> None:
|
|
135
|
+
"""Look up one model ID in the retirement registry."""
|
|
136
|
+
found = load_registry().get(model_id)
|
|
137
|
+
if found is None:
|
|
138
|
+
typer.echo(f"{model_id}: no retirement announced (not in the registry).")
|
|
139
|
+
return
|
|
140
|
+
provider, model = found
|
|
141
|
+
status = model.status_on(date.today())
|
|
142
|
+
if status is Status.RETIRED:
|
|
143
|
+
line = f"RETIRED since {model.shutdown}"
|
|
144
|
+
if model.shutdown_is_earliest:
|
|
145
|
+
line += " (the earliest possible date the provider gave)"
|
|
146
|
+
elif model.shutdown_is_earliest:
|
|
147
|
+
line = f"{status.value.upper()}, shuts down no earlier than {model.shutdown}"
|
|
148
|
+
else:
|
|
149
|
+
line = f"{status.value.upper()}, shuts down on {model.shutdown}"
|
|
150
|
+
typer.echo(f"{model_id} ({provider.value}): {line}.")
|
|
151
|
+
if model.superseded:
|
|
152
|
+
typer.echo(f"Rescheduled: {len(model.superseded)} earlier plan(s) were replaced.")
|
|
153
|
+
if model.replacement:
|
|
154
|
+
typer.echo(f"Suggested replacement: {model.replacement}")
|
modelbump/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Retirement registry: which LLM models are being shut down, and when."""
|
|
2
|
+
|
|
3
|
+
from modelbump.registry.loader import (
|
|
4
|
+
DuplicateModelError,
|
|
5
|
+
Registry,
|
|
6
|
+
load_provider_file,
|
|
7
|
+
load_registry,
|
|
8
|
+
)
|
|
9
|
+
from modelbump.registry.models import (
|
|
10
|
+
EarlierPlan,
|
|
11
|
+
Provider,
|
|
12
|
+
ProviderFile,
|
|
13
|
+
RetiredModel,
|
|
14
|
+
Status,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"DuplicateModelError",
|
|
19
|
+
"EarlierPlan",
|
|
20
|
+
"Provider",
|
|
21
|
+
"ProviderFile",
|
|
22
|
+
"Registry",
|
|
23
|
+
"RetiredModel",
|
|
24
|
+
"Status",
|
|
25
|
+
"load_provider_file",
|
|
26
|
+
"load_registry",
|
|
27
|
+
]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Copied from the "Deprecation history" table of the source page.
|
|
2
|
+
# `announced` is the date of each section on that page; `shutdown` is its
|
|
3
|
+
# "Retirement date". `replacement` is what the page recommends TODAY, which is
|
|
4
|
+
# not always what was recommended at the time (see ADR 0006).
|
|
5
|
+
provider: anthropic
|
|
6
|
+
source_url: https://platform.claude.com/docs/en/about-claude/model-deprecations
|
|
7
|
+
retrieved: 2026-10-08
|
|
8
|
+
models:
|
|
9
|
+
- id: claude-sonnet-4-5-20250929
|
|
10
|
+
announced: 2026-09-30
|
|
11
|
+
shutdown: 2026-11-30
|
|
12
|
+
replacement: claude-sonnet-5-5
|
|
13
|
+
- id: claude-opus-4-1-20250805
|
|
14
|
+
announced: 2026-06-05
|
|
15
|
+
shutdown: 2026-08-05
|
|
16
|
+
replacement: claude-opus-4-8
|
|
17
|
+
- id: claude-sonnet-4-20250514
|
|
18
|
+
announced: 2026-04-14
|
|
19
|
+
shutdown: 2026-06-15
|
|
20
|
+
replacement: claude-sonnet-4-6
|
|
21
|
+
- id: claude-opus-4-20250514
|
|
22
|
+
announced: 2026-04-14
|
|
23
|
+
shutdown: 2026-06-15
|
|
24
|
+
replacement: claude-opus-4-8
|
|
25
|
+
- id: claude-3-haiku-20240307
|
|
26
|
+
announced: 2026-02-19
|
|
27
|
+
shutdown: 2026-04-20
|
|
28
|
+
replacement: claude-haiku-4-5-20251001
|
|
29
|
+
- id: claude-3-5-haiku-20241022
|
|
30
|
+
announced: 2025-12-19
|
|
31
|
+
shutdown: 2026-02-19
|
|
32
|
+
replacement: claude-haiku-4-5-20251001
|
|
33
|
+
- id: claude-3-7-sonnet-20250219
|
|
34
|
+
announced: 2025-10-28
|
|
35
|
+
shutdown: 2026-02-19
|
|
36
|
+
replacement: claude-sonnet-4-6
|
|
37
|
+
- id: claude-3-5-sonnet-20240620
|
|
38
|
+
announced: 2025-08-13
|
|
39
|
+
shutdown: 2025-10-28
|
|
40
|
+
replacement: claude-sonnet-4-6
|
|
41
|
+
- id: claude-3-5-sonnet-20241022
|
|
42
|
+
announced: 2025-08-13
|
|
43
|
+
shutdown: 2025-10-28
|
|
44
|
+
replacement: claude-sonnet-4-6
|
|
45
|
+
- id: claude-3-opus-20240229
|
|
46
|
+
announced: 2025-06-30
|
|
47
|
+
shutdown: 2026-01-05
|
|
48
|
+
replacement: claude-opus-4-8
|
|
49
|
+
- id: claude-2.0
|
|
50
|
+
announced: 2025-01-21
|
|
51
|
+
shutdown: 2025-07-21
|
|
52
|
+
replacement: claude-opus-4-8
|
|
53
|
+
- id: claude-2.1
|
|
54
|
+
announced: 2025-01-21
|
|
55
|
+
shutdown: 2025-07-21
|
|
56
|
+
replacement: claude-opus-4-8
|
|
57
|
+
- id: claude-3-sonnet-20240229
|
|
58
|
+
announced: 2025-01-21
|
|
59
|
+
shutdown: 2025-07-21
|
|
60
|
+
replacement: claude-sonnet-4-6
|
|
61
|
+
- id: claude-1.0
|
|
62
|
+
announced: 2024-09-04
|
|
63
|
+
shutdown: 2024-11-06
|
|
64
|
+
replacement: claude-haiku-4-5-20251001
|
|
65
|
+
- id: claude-1.1
|
|
66
|
+
announced: 2024-09-04
|
|
67
|
+
shutdown: 2024-11-06
|
|
68
|
+
replacement: claude-haiku-4-5-20251001
|
|
69
|
+
- id: claude-1.2
|
|
70
|
+
announced: 2024-09-04
|
|
71
|
+
shutdown: 2024-11-06
|
|
72
|
+
replacement: claude-haiku-4-5-20251001
|
|
73
|
+
- id: claude-1.3
|
|
74
|
+
announced: 2024-09-04
|
|
75
|
+
shutdown: 2024-11-06
|
|
76
|
+
replacement: claude-haiku-4-5-20251001
|
|
77
|
+
- id: claude-instant-1.0
|
|
78
|
+
announced: 2024-09-04
|
|
79
|
+
shutdown: 2024-11-06
|
|
80
|
+
replacement: claude-haiku-4-5-20251001
|
|
81
|
+
- id: claude-instant-1.1
|
|
82
|
+
announced: 2024-09-04
|
|
83
|
+
shutdown: 2024-11-06
|
|
84
|
+
replacement: claude-haiku-4-5-20251001
|
|
85
|
+
- id: claude-instant-1.2
|
|
86
|
+
announced: 2024-09-04
|
|
87
|
+
shutdown: 2024-11-06
|
|
88
|
+
replacement: claude-haiku-4-5-20251001
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Copied from the source page. Scope: Gemini text models and embedding models
|
|
2
|
+
# that have a shutdown date (see docs/architecture/registry.md).
|
|
3
|
+
# The page gives no announcement dates, and says: "The shutdown dates listed in
|
|
4
|
+
# the table indicate the earliest possible dates on which a model might be
|
|
5
|
+
# retired." So every entry has `shutdown_is_earliest: true`.
|
|
6
|
+
# `replacement` is what the page recommends TODAY (see ADR 0006).
|
|
7
|
+
provider: google
|
|
8
|
+
source_url: https://ai.google.dev/gemini-api/docs/deprecations
|
|
9
|
+
retrieved: 2026-10-08
|
|
10
|
+
models:
|
|
11
|
+
- id: gemini-3.1-flash-lite
|
|
12
|
+
shutdown: 2027-05-07
|
|
13
|
+
shutdown_is_earliest: true
|
|
14
|
+
replacement: gemini-3.5-flash-lite
|
|
15
|
+
- id: gemini-3-pro-preview
|
|
16
|
+
shutdown: 2026-03-09
|
|
17
|
+
shutdown_is_earliest: true
|
|
18
|
+
replacement: gemini-3.1-pro-preview
|
|
19
|
+
- id: gemini-3.1-flash-lite-preview
|
|
20
|
+
shutdown: 2026-05-25
|
|
21
|
+
shutdown_is_earliest: true
|
|
22
|
+
replacement: gemini-3.1-flash-lite
|
|
23
|
+
- id: gemini-2.5-computer-use-preview-10-2025
|
|
24
|
+
shutdown: 2026-07-28
|
|
25
|
+
shutdown_is_earliest: true
|
|
26
|
+
replacement: gemini-3.8-flash
|
|
27
|
+
- id: gemini-2.5-pro-preview-03-25
|
|
28
|
+
shutdown: 2025-12-02
|
|
29
|
+
shutdown_is_earliest: true
|
|
30
|
+
replacement: gemini-3.1-pro-preview
|
|
31
|
+
- id: gemini-2.5-pro-preview-05-06
|
|
32
|
+
shutdown: 2025-12-02
|
|
33
|
+
shutdown_is_earliest: true
|
|
34
|
+
replacement: gemini-3.1-pro-preview
|
|
35
|
+
- id: gemini-2.5-pro-preview-06-05
|
|
36
|
+
shutdown: 2025-12-02
|
|
37
|
+
shutdown_is_earliest: true
|
|
38
|
+
replacement: gemini-3.1-pro-preview
|
|
39
|
+
- id: gemini-2.5-flash-lite-preview-09-2025
|
|
40
|
+
shutdown: 2026-03-31
|
|
41
|
+
shutdown_is_earliest: true
|
|
42
|
+
replacement: gemini-3.1-flash-lite
|
|
43
|
+
- id: gemini-2.5-flash-preview-05-20
|
|
44
|
+
shutdown: 2025-11-18
|
|
45
|
+
shutdown_is_earliest: true
|
|
46
|
+
replacement: gemini-3.6-flash
|
|
47
|
+
- id: gemini-2.5-flash-preview-09-25
|
|
48
|
+
shutdown: 2026-02-17
|
|
49
|
+
shutdown_is_earliest: true
|
|
50
|
+
replacement: gemini-3.6-flash
|
|
51
|
+
- id: gemini-2.0-flash
|
|
52
|
+
shutdown: 2026-06-01
|
|
53
|
+
shutdown_is_earliest: true
|
|
54
|
+
replacement: gemini-3.6-flash
|
|
55
|
+
- id: gemini-2.0-flash-001
|
|
56
|
+
shutdown: 2026-06-01
|
|
57
|
+
shutdown_is_earliest: true
|
|
58
|
+
replacement: gemini-3.6-flash
|
|
59
|
+
- id: gemini-2.0-flash-lite
|
|
60
|
+
shutdown: 2026-06-01
|
|
61
|
+
shutdown_is_earliest: true
|
|
62
|
+
replacement: gemini-3.1-flash-lite
|
|
63
|
+
- id: gemini-2.0-flash-lite-001
|
|
64
|
+
shutdown: 2026-06-01
|
|
65
|
+
shutdown_is_earliest: true
|
|
66
|
+
replacement: gemini-3.1-flash-lite
|
|
67
|
+
- id: gemini-2.0-flash-lite-preview
|
|
68
|
+
shutdown: 2025-12-09
|
|
69
|
+
shutdown_is_earliest: true
|
|
70
|
+
replacement: gemini-2.5-flash-lite
|
|
71
|
+
- id: gemini-2.0-flash-lite-preview-02-05
|
|
72
|
+
shutdown: 2025-12-09
|
|
73
|
+
shutdown_is_earliest: true
|
|
74
|
+
replacement: gemini-2.5-flash-lite
|
|
75
|
+
- id: gemini-embedding-001
|
|
76
|
+
shutdown: 2028-05-14
|
|
77
|
+
shutdown_is_earliest: true
|
|
78
|
+
replacement: gemini-embedding-2
|
|
79
|
+
- id: text-embedding-004
|
|
80
|
+
shutdown: 2026-01-14
|
|
81
|
+
shutdown_is_earliest: true
|
|
82
|
+
replacement: gemini-embedding-2
|
|
83
|
+
- id: embedding-2-preview
|
|
84
|
+
shutdown: 2026-08-10
|
|
85
|
+
shutdown_is_earliest: true
|
|
86
|
+
replacement: gemini-embedding-2
|
|
87
|
+
- id: embedding-001
|
|
88
|
+
shutdown: 2025-10-30
|
|
89
|
+
shutdown_is_earliest: true
|
|
90
|
+
replacement: gemini-embedding-2
|
|
91
|
+
- id: embedding-gecko-001
|
|
92
|
+
shutdown: 2025-10-30
|
|
93
|
+
shutdown_is_earliest: true
|
|
94
|
+
replacement: gemini-embedding-2
|
|
95
|
+
- id: gemini-embedding-exp
|
|
96
|
+
shutdown: 2025-10-30
|
|
97
|
+
shutdown_is_earliest: true
|
|
98
|
+
replacement: gemini-embedding-2
|
|
99
|
+
- id: gemini-embedding-exp-03-07
|
|
100
|
+
shutdown: 2025-10-30
|
|
101
|
+
shutdown_is_earliest: true
|
|
102
|
+
replacement: gemini-embedding-2
|