roadmodel 0.2.73__tar.gz → 0.2.74__tar.gz
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.
- {roadmodel-0.2.73 → roadmodel-0.2.74}/PKG-INFO +1 -1
- {roadmodel-0.2.73/roadmodel/data → roadmodel-0.2.74/docs}/catalog.json +1 -1
- {roadmodel-0.2.73 → roadmodel-0.2.74}/pyproject.toml +1 -1
- {roadmodel-0.2.73/docs → roadmodel-0.2.74/roadmodel/data}/catalog.json +1 -1
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/__init__.py +1 -1
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/recommend.py +5 -1
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/scoring.py +50 -7
- {roadmodel-0.2.73 → roadmodel-0.2.74}/.gitignore +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/LICENSE +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/NOTICE +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/README.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/docs/benchmarks.json +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/docs/context-windows.json +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/docs/model-selector.txt +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/docs/model-tier-cost-scale.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/docs/settings-display.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/docs/templates/phase-roadmap-template.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/docs/templates/planning-kit-how-to-use.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/docs/templates/project-roadmap-template.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/docs/templates/prompt-phase-roadmap.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/docs/templates/prompt-project-roadmap.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/docs/user-context.example.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/hatch_build.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/infra/README.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/infra/gcp-killswitch/README.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/infra/supabase/README.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/roadmodel/data/benchmarks.json +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/roadmodel/data/context-windows.json +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/roadmodel/data/model-selector.txt +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/roadmodel/data/model-tier-cost-scale.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/roadmodel/data/phase-roadmap-template.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/roadmodel/data/planning-kit-how-to-use.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/roadmodel/data/project-roadmap-template.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/roadmodel/data/prompt-phase-roadmap.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/roadmodel/data/prompt-project-roadmap.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/roadmodel/data/settings-display.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/roadmodel/data/user-context.example.md +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/scripts/agent_context.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/scripts/agent_rules.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/scripts/update_projects.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/scripts/updater_lock.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/scripts/upgrade_fleet.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/scripts/worktree_memory.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/__main__.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/cli.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/config.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/cost.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/errors.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/mcp_server.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/providers/__init__.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/providers/anthropic.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/providers/google.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/providers/openai.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/providers/openai_compatible.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/providers/registry.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/usage.py +0 -0
- {roadmodel-0.2.73 → roadmodel-0.2.74}/src/roadmodel/user_context.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: roadmodel
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.74
|
|
4
4
|
Summary: BYO-key CLI that recommends the right AI model, platform, and settings for a prompt.
|
|
5
5
|
Project-URL: Homepage, https://roadmodel.ai
|
|
6
6
|
Project-URL: Repository, https://github.com/nathanramoscfa/roadmodel
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "4",
|
|
3
3
|
"output_contract_version": 2,
|
|
4
|
-
"generated_at_utc": "2026-10-
|
|
4
|
+
"generated_at_utc": "2026-10-07T20:14:28Z",
|
|
5
5
|
"source_doc_sha256": {
|
|
6
6
|
"model-selector.txt": "6a75e2265459fa7302cb80d0faf5ec2aad575034fc29866238cd1579c001cc2d",
|
|
7
7
|
"model-tier-cost-scale.md": "2b3b0eb82237eb5cb5bf468a3fe971bcaf0160ad7d0bc700698d2c16640bc41d"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "4",
|
|
3
3
|
"output_contract_version": 2,
|
|
4
|
-
"generated_at_utc": "2026-10-
|
|
4
|
+
"generated_at_utc": "2026-10-07T20:14:28Z",
|
|
5
5
|
"source_doc_sha256": {
|
|
6
6
|
"model-selector.txt": "6a75e2265459fa7302cb80d0faf5ec2aad575034fc29866238cd1579c001cc2d",
|
|
7
7
|
"model-tier-cost-scale.md": "2b3b0eb82237eb5cb5bf468a3fe971bcaf0160ad7d0bc700698d2c16640bc41d"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# src/roadmodel/__init__.py
|
|
2
|
-
__version__ = "0.2.
|
|
2
|
+
__version__ = "0.2.74"
|
|
@@ -479,7 +479,11 @@ _SAAS_LADDER_TABLE_HEADER: Final = (
|
|
|
479
479
|
"1. One line `CLASSIFICATION: <category> / <complexity> / <novel|routine>`. "
|
|
480
480
|
"<category> is the task's PRIMARY category (coding, planning, agentic, multimodal, "
|
|
481
481
|
"long-context, knowledge or speed) per Step 1 of the selection algorithm; "
|
|
482
|
-
"<complexity> is low, medium or high per its Step 2.
|
|
482
|
+
"<complexity> is low, medium or high per its Step 2. High-volume routine work "
|
|
483
|
+
"(classifying, tagging, extracting or summarizing many similar items) is `speed` "
|
|
484
|
+
"whatever accuracy it needs, and its complexity is how hard ONE item is. Building an "
|
|
485
|
+
"agent or an app (writing its code) is `coding`; running one, where the model itself "
|
|
486
|
+
"acts through tools in a loop, is `agentic`. `novel` marks "
|
|
483
487
|
"research-grade work only: an open problem, a new algorithm, or a proof of a "
|
|
484
488
|
"result with no known proof. Writing out a known result (a textbook proof, a "
|
|
485
489
|
"standard derivation) is `routine` however many steps it takes, and its "
|
|
@@ -961,10 +961,20 @@ def rank(
|
|
|
961
961
|
catalog: dict[str, Any] | None = None,
|
|
962
962
|
benchmarks: dict[str, Any] | None = None,
|
|
963
963
|
top: int | None = None,
|
|
964
|
+
effort_aware: bool = True,
|
|
964
965
|
) -> Ranking:
|
|
965
|
-
"""Rank every reachable (model, platform) pair for ``task``.
|
|
966
|
+
"""Rank every reachable (model, platform) pair for ``task``.
|
|
967
|
+
|
|
968
|
+
With ``effort_aware`` (the default), a model AA has measured at several
|
|
969
|
+
efforts stands at the one that scores best for the task's posture, among
|
|
970
|
+
those it may run (:func:`effort_settings`), its quality, requirement
|
|
971
|
+
penalty (in the category and in general capability) and cost read there;
|
|
972
|
+
a model measured only at efforts the task does not run is left out. Off,
|
|
973
|
+
every model stands on its headline row at its posture's effort: the pool
|
|
974
|
+
:func:`ladder` expands itself."""
|
|
966
975
|
cat = catalog if catalog is not None else _cost._load_catalog()
|
|
967
|
-
|
|
976
|
+
raw_bench = benchmarks if benchmarks is not None else _load_benchmarks()
|
|
977
|
+
bench = with_composites(raw_bench)
|
|
968
978
|
text = user_context_text or ""
|
|
969
979
|
headroom = consumption_headroom(text)
|
|
970
980
|
pools = pool_states(text)
|
|
@@ -1100,6 +1110,28 @@ def rank(
|
|
|
1100
1110
|
continue
|
|
1101
1111
|
candidates.append(best_for_model)
|
|
1102
1112
|
|
|
1113
|
+
if effort_aware and candidates:
|
|
1114
|
+
settings = effort_settings(
|
|
1115
|
+
candidates, task, headroom, lam=lam, k=k, catalog=cat, benchmarks=raw_bench
|
|
1116
|
+
)
|
|
1117
|
+
best: dict[str, Candidate] = {}
|
|
1118
|
+
for c in settings:
|
|
1119
|
+
held = best.get(c.model_id)
|
|
1120
|
+
if held is None or (c.score, -c.effective_cost_usd) > (
|
|
1121
|
+
held.score,
|
|
1122
|
+
-held.effective_cost_usd,
|
|
1123
|
+
):
|
|
1124
|
+
best[c.model_id] = c
|
|
1125
|
+
for c in candidates:
|
|
1126
|
+
if c.model_id not in best:
|
|
1127
|
+
excluded.append(
|
|
1128
|
+
{
|
|
1129
|
+
"model": c.model_id,
|
|
1130
|
+
"reason": "measured only at efforts this task does not run",
|
|
1131
|
+
}
|
|
1132
|
+
)
|
|
1133
|
+
candidates = [best[c.model_id] for c in candidates if c.model_id in best]
|
|
1134
|
+
|
|
1103
1135
|
# Funded first, then score, then cheaper, then id — deterministic.
|
|
1104
1136
|
candidates.sort(
|
|
1105
1137
|
key=lambda c: (c.funding == "unfunded", -c.score, c.effective_cost_usd, c.model_id)
|
|
@@ -1404,7 +1436,8 @@ def _at_level(
|
|
|
1404
1436
|
task: Task,
|
|
1405
1437
|
bench: dict[str, Any],
|
|
1406
1438
|
scales: tuple[EvidenceScale | None, EvidenceScale | None],
|
|
1407
|
-
|
|
1439
|
+
lam: float,
|
|
1440
|
+
k: float,
|
|
1408
1441
|
) -> Candidate:
|
|
1409
1442
|
"""``c`` run at ``level`` (None: its headline row, at the posture's
|
|
1410
1443
|
effort): quality from AA's row at that effort, and the requirement
|
|
@@ -1434,7 +1467,7 @@ def _at_level(
|
|
|
1434
1467
|
mult = EFFORT_TOKEN_MULTIPLIER[level]
|
|
1435
1468
|
eff_cost = c.blended_price_usd * c.scarcity * mult
|
|
1436
1469
|
decades = math.log10(max(eff_cost, COST_FLOOR_USD) / COST_FLOOR_USD)
|
|
1437
|
-
cost_pen =
|
|
1470
|
+
cost_pen = lam * k * decades
|
|
1438
1471
|
nudge = 0.5 if task.category in AGENT_CATEGORIES and c.platform_id in AGENT_SURFACES else 0.0
|
|
1439
1472
|
return replace(
|
|
1440
1473
|
c,
|
|
@@ -1457,8 +1490,9 @@ def effort_settings(
|
|
|
1457
1490
|
pool: list[Candidate],
|
|
1458
1491
|
task: Task,
|
|
1459
1492
|
headroom: str,
|
|
1460
|
-
ranking: Ranking,
|
|
1461
1493
|
*,
|
|
1494
|
+
lam: float,
|
|
1495
|
+
k: float,
|
|
1462
1496
|
catalog: dict[str, Any],
|
|
1463
1497
|
benchmarks: dict[str, Any],
|
|
1464
1498
|
) -> list[Candidate]:
|
|
@@ -1493,7 +1527,7 @@ def effort_settings(
|
|
|
1493
1527
|
if headroom == "uncapped" and c.scarcity == 0:
|
|
1494
1528
|
levels = levels[-1:] # a free path runs at its top effort
|
|
1495
1529
|
out.extend(
|
|
1496
|
-
_at_level(c, lv, model, task, bench, scales,
|
|
1530
|
+
_at_level(c, lv, model, task, bench, scales, lam, k) for lv in (levels or [None])
|
|
1497
1531
|
)
|
|
1498
1532
|
return out
|
|
1499
1533
|
|
|
@@ -1558,6 +1592,7 @@ def ladder(
|
|
|
1558
1592
|
unavailable_models=unavailable_models,
|
|
1559
1593
|
catalog=cat,
|
|
1560
1594
|
benchmarks=bench,
|
|
1595
|
+
effort_aware=False,
|
|
1561
1596
|
)
|
|
1562
1597
|
funded = [c for c in ranking.candidates if c.funding != "unfunded"]
|
|
1563
1598
|
pool = funded or ranking.candidates
|
|
@@ -1567,7 +1602,15 @@ def ladder(
|
|
|
1567
1602
|
headroom = consumption_headroom(user_context_text or "")
|
|
1568
1603
|
# The picks are read off the same frontier drawn over each model at every
|
|
1569
1604
|
# effort AA measured it at, so an effort is part of the pick it prices.
|
|
1570
|
-
settings = effort_settings(
|
|
1605
|
+
settings = effort_settings(
|
|
1606
|
+
pool,
|
|
1607
|
+
base,
|
|
1608
|
+
headroom,
|
|
1609
|
+
lam=ranking.lam,
|
|
1610
|
+
k=ranking.k_points_per_decade,
|
|
1611
|
+
catalog=cat,
|
|
1612
|
+
benchmarks=bench,
|
|
1613
|
+
)
|
|
1571
1614
|
# Every model AA measured only at efforts this task does not run leaves
|
|
1572
1615
|
# none: the picks then fall back to the models' frontier.
|
|
1573
1616
|
points = frontier(settings, bench) or front
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|