AbteeXAILabs commited on
Commit
cd63634
·
verified ·
1 Parent(s): ba6bd26

Publish expanded LumynaX product platform package

Browse files
Files changed (4) hide show
  1. PYPI_RELEASE.md +1 -1
  2. marama_route/cli.py +213 -27
  3. marama_route/compat.py +21 -3
  4. pyproject.toml +1 -1
PYPI_RELEASE.md CHANGED
@@ -1,7 +1,7 @@
1
  # PyPI Release: LumynaX MaramaRoute
2
 
3
  Package: `lumynax-marama-route`
4
- Version: `0.7.11`
5
 
6
  ## Local Build
7
 
 
1
  # PyPI Release: LumynaX MaramaRoute
2
 
3
  Package: `lumynax-marama-route`
4
+ Version: `0.7.12`
5
 
6
  ## Local Build
7
 
marama_route/cli.py CHANGED
@@ -89,11 +89,22 @@ MODEL_PICKER_COMMANDS = {
89
  "/search",
90
  "/switch",
91
  "/use",
 
 
 
 
92
  "/recommended",
93
  "/recommend",
94
  "?",
95
  }
96
  MODEL_PICKER_PAGE_SIZE = 12
 
 
 
 
 
 
 
97
 
98
 
99
  class _ExitConversation(Exception):
@@ -961,6 +972,9 @@ def _conversation(args: argparse.Namespace, models: tuple[Any, ...]) -> int:
961
  "/hardware",
962
  "/recommended",
963
  "/categories",
 
 
 
964
  "/search <text>",
965
  "/switch <text>",
966
  "/pull [text]",
@@ -1062,6 +1076,17 @@ def _conversation(args: argparse.Namespace, models: tuple[Any, ...]) -> int:
1062
  return 0
1063
  session = None
1064
  continue
 
 
 
 
 
 
 
 
 
 
 
1065
  if command == "/catalog":
1066
  choices = _conversation_choices(models, include_all=True)
1067
  _print_model_picker_header(
@@ -1070,6 +1095,7 @@ def _conversation(args: argparse.Namespace, models: tuple[Any, ...]) -> int:
1070
  query="",
1071
  include_all=True,
1072
  hardware_only=False,
 
1073
  offset=0,
1074
  shown=min(len(choices), MODEL_PICKER_PAGE_SIZE),
1075
  hardware=None,
@@ -1271,13 +1297,17 @@ def _conversation_choices(
1271
  *,
1272
  search: str = "",
1273
  include_all: bool = False,
 
1274
  limit: int | None = None,
1275
  ) -> list[Any]:
1276
  filtered: list[Any] = []
1277
  query = search.strip().lower()
1278
  for model in models:
1279
  haystack = " ".join((model.model_id, model.repo_id, model.family, " ".join(model.tags))).lower()
1280
- if not include_all and not _is_chat_runnable(model):
 
 
 
1281
  continue
1282
  if query and query not in haystack:
1283
  continue
@@ -1326,16 +1356,17 @@ def _prompt_for_model(
1326
  initial_query: str = "",
1327
  include_all: bool = False,
1328
  hardware_only: bool = False,
 
1329
  show_menu: bool = True,
1330
  ) -> Any:
1331
  query = initial_query
1332
- menu_open = show_menu and not initial_query and not include_all and not hardware_only
1333
  offset = 0
1334
  last_hardware: dict[str, Any] | None = None
1335
  while True:
1336
  if menu_open:
1337
  _print_model_picker_menu(models, cache_dir)
1338
- raw = input("Choose option 1-6, type search text, or /exit: ").strip()
1339
  if not raw:
1340
  raw = "1"
1341
  lowered = raw.lower()
@@ -1347,6 +1378,7 @@ def _prompt_for_model(
1347
  if raw == "1" or lowered in {"/hardware", "/recommended-hardware"}:
1348
  hardware_only = True
1349
  include_all = False
 
1350
  query = ""
1351
  offset = 0
1352
  menu_open = False
@@ -1354,6 +1386,7 @@ def _prompt_for_model(
1354
  if raw == "2" or lowered in {"/recommended", "/recommend", "/best"}:
1355
  hardware_only = False
1356
  include_all = False
 
1357
  query = ""
1358
  offset = 0
1359
  menu_open = False
@@ -1362,12 +1395,14 @@ def _prompt_for_model(
1362
  query = input("Search text: ").strip()
1363
  include_all = True
1364
  hardware_only = False
 
1365
  offset = 0
1366
  menu_open = False
1367
  continue
1368
  if raw == "4" or lowered in {"/models", "/switch", "/runnable"}:
1369
  hardware_only = False
1370
  include_all = False
 
1371
  query = ""
1372
  offset = 0
1373
  menu_open = False
@@ -1375,6 +1410,7 @@ def _prompt_for_model(
1375
  if raw == "5" or lowered in {"/all", "/catalog"}:
1376
  hardware_only = False
1377
  include_all = True
 
1378
  query = ""
1379
  offset = 0
1380
  menu_open = False
@@ -1382,22 +1418,56 @@ def _prompt_for_model(
1382
  if raw == "6" or lowered == "/local":
1383
  _print_local_models(cache_dir)
1384
  continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1385
  handled = _handle_model_picker_command(raw, models)
1386
  if handled is not None:
1387
  query = handled["query"]
1388
  include_all = handled["include_all"]
1389
  hardware_only = handled.get("hardware_only", False)
 
1390
  menu_open = handled.get("menu", False)
1391
  offset = 0
1392
  else:
1393
  query = raw
1394
  include_all = True
1395
  hardware_only = False
 
1396
  offset = 0
1397
  menu_open = False
1398
  continue
1399
 
1400
- if hardware_only:
 
 
 
 
 
 
 
 
1401
  choices, last_hardware = _hardware_choices(models, cache_dir, search=query, include_all=include_all)
1402
  else:
1403
  choices = _conversation_choices(models, search=query, include_all=include_all)
@@ -1409,6 +1479,7 @@ def _prompt_for_model(
1409
  query = handled["query"]
1410
  include_all = handled["include_all"]
1411
  hardware_only = handled.get("hardware_only", False)
 
1412
  menu_open = handled.get("menu", False)
1413
  offset = 0
1414
  else:
@@ -1423,6 +1494,7 @@ def _prompt_for_model(
1423
  query=query,
1424
  include_all=include_all,
1425
  hardware_only=hardware_only,
 
1426
  offset=offset,
1427
  shown=len(page),
1428
  hardware=last_hardware,
@@ -1457,6 +1529,7 @@ def _prompt_for_model(
1457
  query = handled["query"]
1458
  include_all = handled["include_all"]
1459
  hardware_only = handled.get("hardware_only", False)
 
1460
  menu_open = handled.get("menu", False)
1461
  offset = 0
1462
  continue
@@ -1482,42 +1555,49 @@ def _handle_model_picker_command(raw: str, models: tuple[Any, ...]) -> dict[str,
1482
  if command in CHAT_COMMANDS:
1483
  raise _ExitConversation
1484
  if command in {"/models", "/switch", "/runnable"}:
1485
- return {"query": "", "include_all": False, "hardware_only": False}
1486
  if command in {"/hardware", "/recommended-hardware"}:
1487
- return {"query": "", "include_all": False, "hardware_only": True}
1488
  if command in {"/recommended", "/recommend", "/best"}:
1489
- return {"query": "", "include_all": False, "hardware_only": False}
1490
  if command == "/menu":
1491
- return {"query": "", "include_all": False, "hardware_only": False, "menu": True}
1492
  if command == "/all":
1493
- return {"query": "", "include_all": True, "hardware_only": False}
1494
  if command == "/catalog":
1495
- return {"query": "", "include_all": True, "hardware_only": False}
 
 
 
 
 
 
 
1496
  if command.startswith("/search "):
1497
  query = command.removeprefix("/search ").strip()
1498
- return {"query": query, "include_all": True, "hardware_only": False}
1499
  if command.startswith("/use "):
1500
  query = command.removeprefix("/use ").strip()
1501
- return {"query": query, "include_all": False, "hardware_only": False}
1502
  if command.startswith("/family "):
1503
  family = command.removeprefix("/family ").strip()
1504
- return {"query": family, "include_all": True, "hardware_only": False}
1505
  if command in {"/families", "/categories"}:
1506
  _print_model_categories(models)
1507
- return {"query": "", "include_all": True, "hardware_only": False}
1508
  if command == "/local":
1509
  print("Local models are shown after a model is selected. Use `MaramaRoute local` for full JSON.")
1510
- return {"query": "", "include_all": False, "hardware_only": False, "menu": True}
1511
  if command in {"/help", "/h", "?"}:
1512
  _print_model_picker_help()
1513
- return {"query": "", "include_all": False, "hardware_only": False, "menu": True}
1514
  if command == "/pull":
1515
  print("Choose a model first; then /pull downloads the selected model.")
1516
- return {"query": "", "include_all": False, "hardware_only": False}
1517
  if command.startswith("/"):
1518
  known = ", ".join(sorted(CHAT_COMMANDS | MODEL_PICKER_COMMANDS))
1519
  print(f"Unknown command {raw!r}. Known commands: {known}.")
1520
- return {"query": "", "include_all": False, "hardware_only": False, "menu": True}
1521
  return None
1522
 
1523
 
@@ -1538,6 +1618,86 @@ def _offline_capability_label(model: Any) -> str:
1538
  return "offline-task"
1539
 
1540
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1541
  def _is_transformers_text_generation(model: Any) -> bool:
1542
  runtime = model.runtime.lower()
1543
  if "transformers" not in runtime or "multimodal" in runtime:
@@ -1608,13 +1768,16 @@ def _print_model_picker_header(
1608
  query: str,
1609
  include_all: bool,
1610
  hardware_only: bool,
 
1611
  offset: int,
1612
  shown: int,
1613
  hardware: dict[str, Any] | None,
1614
  ) -> None:
1615
  total = len(models)
1616
  runnable = sum(1 for model in models if _is_chat_runnable(model))
1617
- if hardware_only:
 
 
1618
  scope = "hardware-suitable local GGUF chat models"
1619
  else:
1620
  scope = "all AbteeXAILab HF registry entries" if include_all else "recommended local GGUF chat models"
@@ -1628,10 +1791,12 @@ def _print_model_picker_header(
1628
  print("Use /next for more results.")
1629
  if offset > 0:
1630
  print("Use /prev for previous results.")
1631
- if not include_all and not hardware_only:
1632
- print("Use /hardware for machine-suitable models, /all for the full registry, or /help for commands.")
 
 
1633
  else:
1634
- print("Use /models to return to recommended chat models, /family <name> to filter, or /help for commands.")
1635
 
1636
 
1637
  def _print_model_picker_menu(models: tuple[Any, ...], cache_dir: Path | None) -> None:
@@ -1647,6 +1812,9 @@ def _print_model_picker_menu(models: tuple[Any, ...], cache_dir: Path | None) ->
1647
  print(" 4. Browse local GGUF chat models")
1648
  print(" 5. Browse full registry")
1649
  print(" 6. Show pulled local models")
 
 
 
1650
 
1651
 
1652
  def _print_model_picker_help() -> None:
@@ -1658,9 +1826,13 @@ def _print_model_picker_help() -> None:
1658
  " /recommended show recommended local chat models",
1659
  " /models browse local GGUF chat-capable models",
1660
  " /all browse every bundled AbteeXAILab registry entry",
 
 
 
 
1661
  " /search <text> search model id, repo, family, or tags",
1662
  " /family <name> filter by family or tag",
1663
- " /categories show category/family/runtime/tag counts",
1664
  " /families alias for /categories",
1665
  " /next next page of results",
1666
  " /prev previous page of results",
@@ -1674,7 +1846,7 @@ def _print_model_picker_help() -> None:
1674
 
1675
  def _print_model_categories(models: tuple[Any, ...]) -> None:
1676
  _print_category_summary(_category_summary(models, limit=18))
1677
- print("Type a family/tag/search term, or use /family qwen, /family vision, /all, /runnable.")
1678
 
1679
 
1680
  def _category_summary(models: tuple[Any, ...], *, limit: int) -> dict[str, Any]:
@@ -1702,6 +1874,7 @@ def _category_summary(models: tuple[Any, ...], *, limit: int) -> dict[str, Any]:
1702
  "tags": dict(_top_counts(tags, limit=safe_limit)),
1703
  "modalities": dict(_top_counts(modalities, limit=safe_limit)),
1704
  "capabilities": dict(_top_counts(capabilities, limit=safe_limit)),
 
1705
  "commands": {
1706
  "browse_recommended": "MaramaRoute chat",
1707
  "browse_all": "MaramaRoute catalog",
@@ -1709,6 +1882,9 @@ def _category_summary(models: tuple[Any, ...], *, limit: int) -> dict[str, Any]:
1709
  "filter_family": "MaramaRoute catalog --family qwen",
1710
  "pull_family": "MaramaRoute pull --family qwen --limit 3 --dry-run",
1711
  "compatibility": "MaramaRoute compat",
 
 
 
1712
  },
1713
  }
1714
 
@@ -1722,7 +1898,13 @@ def _print_category_summary(summary: dict[str, Any]) -> None:
1722
  print(f"Runtimes: {_format_counts(summary['runtimes'])}")
1723
  print(f"Modalities: {_format_counts(summary['modalities'])}")
1724
  print(f"Tags: {_format_counts(summary['tags'])}")
1725
- print("Next: MaramaRoute chat | MaramaRoute catalog --family qwen | MaramaRoute pull --family qwen --dry-run")
 
 
 
 
 
 
1726
 
1727
 
1728
  def _format_counts(counts: dict[str, int]) -> str:
@@ -1988,7 +2170,11 @@ def build_parser() -> argparse.ArgumentParser:
1988
  compat.add_argument("model", nargs="?", help="Optional model id, repo id, or unique search fragment.")
1989
  compat.add_argument("--registry", type=Path, default=None, help="MaramaRoute model registry JSON.")
1990
  compat.add_argument("--target", default="", help="Runtime target: vllm, nim, nem, nemo, llama-cpp, or all.")
1991
- compat.add_argument("--status", default="", help="Filter by status such as candidate, experimental, unsupported.")
 
 
 
 
1992
  compat.add_argument("--limit", type=int, default=0, help="Maximum rows; 0 means all models.")
1993
  compat.add_argument("--format", choices=["json", "table"], default="table")
1994
  compat.set_defaults(handler=_compat)
@@ -1996,7 +2182,7 @@ def build_parser() -> argparse.ArgumentParser:
1996
  categories = subparsers.add_parser(
1997
  "categories",
1998
  aliases=["families"],
1999
- help="Show model families, runtimes, tags, modalities, and local capability categories.",
2000
  )
2001
  categories.add_argument("--registry", type=Path, default=None, help="MaramaRoute model registry JSON.")
2002
  categories.add_argument("--limit", type=int, default=18)
 
89
  "/search",
90
  "/switch",
91
  "/use",
92
+ "/vllm",
93
+ "/nim",
94
+ "/nem",
95
+ "/nemo",
96
  "/recommended",
97
  "/recommend",
98
  "?",
99
  }
100
  MODEL_PICKER_PAGE_SIZE = 12
101
+ _DEPLOYMENT_USABLE_STATUSES = {"supported", "candidate", "experimental"}
102
+ _DEPLOYMENT_PATHWAY_STATUSES = _DEPLOYMENT_USABLE_STATUSES | {"convert_required"}
103
+ _DEPLOYMENT_TARGET_LABELS = {
104
+ "vllm": "vLLM",
105
+ "nvidia_nim": "NVIDIA NIM",
106
+ "nvidia_nemo": "NVIDIA NeMo/NEM",
107
+ }
108
 
109
 
110
  class _ExitConversation(Exception):
 
972
  "/hardware",
973
  "/recommended",
974
  "/categories",
975
+ "/vllm",
976
+ "/nim",
977
+ "/nemo",
978
  "/search <text>",
979
  "/switch <text>",
980
  "/pull [text]",
 
1076
  return 0
1077
  session = None
1078
  continue
1079
+ if command in {"/vllm", "/nim", "/nemo", "/nem"}:
1080
+ try:
1081
+ model = _prompt_for_model(
1082
+ models,
1083
+ args.cache_dir,
1084
+ compatibility_target=_deployment_target_from_command(command),
1085
+ )
1086
+ except _ExitConversation:
1087
+ return 0
1088
+ session = None
1089
+ continue
1090
  if command == "/catalog":
1091
  choices = _conversation_choices(models, include_all=True)
1092
  _print_model_picker_header(
 
1095
  query="",
1096
  include_all=True,
1097
  hardware_only=False,
1098
+ compatibility_target="",
1099
  offset=0,
1100
  shown=min(len(choices), MODEL_PICKER_PAGE_SIZE),
1101
  hardware=None,
 
1297
  *,
1298
  search: str = "",
1299
  include_all: bool = False,
1300
+ compatibility_target: str = "",
1301
  limit: int | None = None,
1302
  ) -> list[Any]:
1303
  filtered: list[Any] = []
1304
  query = search.strip().lower()
1305
  for model in models:
1306
  haystack = " ".join((model.model_id, model.repo_id, model.family, " ".join(model.tags))).lower()
1307
+ if compatibility_target:
1308
+ if not _matches_deployment_target(model, compatibility_target):
1309
+ continue
1310
+ elif not include_all and not _is_chat_runnable(model):
1311
  continue
1312
  if query and query not in haystack:
1313
  continue
 
1356
  initial_query: str = "",
1357
  include_all: bool = False,
1358
  hardware_only: bool = False,
1359
+ compatibility_target: str = "",
1360
  show_menu: bool = True,
1361
  ) -> Any:
1362
  query = initial_query
1363
+ menu_open = show_menu and not initial_query and not include_all and not hardware_only and not compatibility_target
1364
  offset = 0
1365
  last_hardware: dict[str, Any] | None = None
1366
  while True:
1367
  if menu_open:
1368
  _print_model_picker_menu(models, cache_dir)
1369
+ raw = input("Choose option 1-9, type search text, or /exit: ").strip()
1370
  if not raw:
1371
  raw = "1"
1372
  lowered = raw.lower()
 
1378
  if raw == "1" or lowered in {"/hardware", "/recommended-hardware"}:
1379
  hardware_only = True
1380
  include_all = False
1381
+ compatibility_target = ""
1382
  query = ""
1383
  offset = 0
1384
  menu_open = False
 
1386
  if raw == "2" or lowered in {"/recommended", "/recommend", "/best"}:
1387
  hardware_only = False
1388
  include_all = False
1389
+ compatibility_target = ""
1390
  query = ""
1391
  offset = 0
1392
  menu_open = False
 
1395
  query = input("Search text: ").strip()
1396
  include_all = True
1397
  hardware_only = False
1398
+ compatibility_target = ""
1399
  offset = 0
1400
  menu_open = False
1401
  continue
1402
  if raw == "4" or lowered in {"/models", "/switch", "/runnable"}:
1403
  hardware_only = False
1404
  include_all = False
1405
+ compatibility_target = ""
1406
  query = ""
1407
  offset = 0
1408
  menu_open = False
 
1410
  if raw == "5" or lowered in {"/all", "/catalog"}:
1411
  hardware_only = False
1412
  include_all = True
1413
+ compatibility_target = ""
1414
  query = ""
1415
  offset = 0
1416
  menu_open = False
 
1418
  if raw == "6" or lowered == "/local":
1419
  _print_local_models(cache_dir)
1420
  continue
1421
+ if raw == "7" or lowered == "/vllm":
1422
+ hardware_only = False
1423
+ include_all = True
1424
+ compatibility_target = "vllm"
1425
+ query = ""
1426
+ offset = 0
1427
+ menu_open = False
1428
+ continue
1429
+ if raw == "8" or lowered == "/nim":
1430
+ hardware_only = False
1431
+ include_all = True
1432
+ compatibility_target = "nvidia_nim"
1433
+ query = ""
1434
+ offset = 0
1435
+ menu_open = False
1436
+ continue
1437
+ if raw == "9" or lowered in {"/nemo", "/nem"}:
1438
+ hardware_only = False
1439
+ include_all = True
1440
+ compatibility_target = "nvidia_nemo"
1441
+ query = ""
1442
+ offset = 0
1443
+ menu_open = False
1444
+ continue
1445
  handled = _handle_model_picker_command(raw, models)
1446
  if handled is not None:
1447
  query = handled["query"]
1448
  include_all = handled["include_all"]
1449
  hardware_only = handled.get("hardware_only", False)
1450
+ compatibility_target = handled.get("compatibility_target", "")
1451
  menu_open = handled.get("menu", False)
1452
  offset = 0
1453
  else:
1454
  query = raw
1455
  include_all = True
1456
  hardware_only = False
1457
+ compatibility_target = ""
1458
  offset = 0
1459
  menu_open = False
1460
  continue
1461
 
1462
+ if compatibility_target:
1463
+ choices = _conversation_choices(
1464
+ models,
1465
+ search=query,
1466
+ include_all=True,
1467
+ compatibility_target=compatibility_target,
1468
+ )
1469
+ last_hardware = None
1470
+ elif hardware_only:
1471
  choices, last_hardware = _hardware_choices(models, cache_dir, search=query, include_all=include_all)
1472
  else:
1473
  choices = _conversation_choices(models, search=query, include_all=include_all)
 
1479
  query = handled["query"]
1480
  include_all = handled["include_all"]
1481
  hardware_only = handled.get("hardware_only", False)
1482
+ compatibility_target = handled.get("compatibility_target", "")
1483
  menu_open = handled.get("menu", False)
1484
  offset = 0
1485
  else:
 
1494
  query=query,
1495
  include_all=include_all,
1496
  hardware_only=hardware_only,
1497
+ compatibility_target=compatibility_target,
1498
  offset=offset,
1499
  shown=len(page),
1500
  hardware=last_hardware,
 
1529
  query = handled["query"]
1530
  include_all = handled["include_all"]
1531
  hardware_only = handled.get("hardware_only", False)
1532
+ compatibility_target = handled.get("compatibility_target", "")
1533
  menu_open = handled.get("menu", False)
1534
  offset = 0
1535
  continue
 
1555
  if command in CHAT_COMMANDS:
1556
  raise _ExitConversation
1557
  if command in {"/models", "/switch", "/runnable"}:
1558
+ return {"query": "", "include_all": False, "hardware_only": False, "compatibility_target": ""}
1559
  if command in {"/hardware", "/recommended-hardware"}:
1560
+ return {"query": "", "include_all": False, "hardware_only": True, "compatibility_target": ""}
1561
  if command in {"/recommended", "/recommend", "/best"}:
1562
+ return {"query": "", "include_all": False, "hardware_only": False, "compatibility_target": ""}
1563
  if command == "/menu":
1564
+ return {"query": "", "include_all": False, "hardware_only": False, "compatibility_target": "", "menu": True}
1565
  if command == "/all":
1566
+ return {"query": "", "include_all": True, "hardware_only": False, "compatibility_target": ""}
1567
  if command == "/catalog":
1568
+ return {"query": "", "include_all": True, "hardware_only": False, "compatibility_target": ""}
1569
+ if command in {"/vllm", "/nim", "/nemo", "/nem"}:
1570
+ return {
1571
+ "query": "",
1572
+ "include_all": True,
1573
+ "hardware_only": False,
1574
+ "compatibility_target": _deployment_target_from_command(command),
1575
+ }
1576
  if command.startswith("/search "):
1577
  query = command.removeprefix("/search ").strip()
1578
+ return {"query": query, "include_all": True, "hardware_only": False, "compatibility_target": ""}
1579
  if command.startswith("/use "):
1580
  query = command.removeprefix("/use ").strip()
1581
+ return {"query": query, "include_all": False, "hardware_only": False, "compatibility_target": ""}
1582
  if command.startswith("/family "):
1583
  family = command.removeprefix("/family ").strip()
1584
+ return {"query": family, "include_all": True, "hardware_only": False, "compatibility_target": ""}
1585
  if command in {"/families", "/categories"}:
1586
  _print_model_categories(models)
1587
+ return {"query": "", "include_all": True, "hardware_only": False, "compatibility_target": ""}
1588
  if command == "/local":
1589
  print("Local models are shown after a model is selected. Use `MaramaRoute local` for full JSON.")
1590
+ return {"query": "", "include_all": False, "hardware_only": False, "compatibility_target": "", "menu": True}
1591
  if command in {"/help", "/h", "?"}:
1592
  _print_model_picker_help()
1593
+ return {"query": "", "include_all": False, "hardware_only": False, "compatibility_target": "", "menu": True}
1594
  if command == "/pull":
1595
  print("Choose a model first; then /pull downloads the selected model.")
1596
+ return {"query": "", "include_all": False, "hardware_only": False, "compatibility_target": ""}
1597
  if command.startswith("/"):
1598
  known = ", ".join(sorted(CHAT_COMMANDS | MODEL_PICKER_COMMANDS))
1599
  print(f"Unknown command {raw!r}. Known commands: {known}.")
1600
+ return {"query": "", "include_all": False, "hardware_only": False, "compatibility_target": "", "menu": True}
1601
  return None
1602
 
1603
 
 
1618
  return "offline-task"
1619
 
1620
 
1621
+ def _deployment_target_from_command(command: str) -> str:
1622
+ normalized = command.strip().lower().lstrip("/").replace("-", "_")
1623
+ if normalized == "vllm":
1624
+ return "vllm"
1625
+ if normalized == "nim":
1626
+ return "nvidia_nim"
1627
+ if normalized in {"nem", "nemo"}:
1628
+ return "nvidia_nemo"
1629
+ raise ValueError(f"Unknown deployment target command: {command}")
1630
+
1631
+
1632
+ def _deployment_statuses_for_target(target: str) -> set[str]:
1633
+ if target == "nvidia_nemo":
1634
+ return set(_DEPLOYMENT_PATHWAY_STATUSES)
1635
+ return set(_DEPLOYMENT_USABLE_STATUSES)
1636
+
1637
+
1638
+ def _matches_deployment_target(model: Any, target: str) -> bool:
1639
+ compatibility = model_runtime_compatibility(model)
1640
+ entry = compatibility.get(target, {})
1641
+ status = str(entry.get("status") or "").lower() if isinstance(entry, dict) else ""
1642
+ return status in _deployment_statuses_for_target(target)
1643
+
1644
+
1645
+ def _deployment_summary(models: tuple[Any, ...]) -> dict[str, Any]:
1646
+ summary: dict[str, Any] = {}
1647
+ for target, label in _DEPLOYMENT_TARGET_LABELS.items():
1648
+ statuses: dict[str, int] = {}
1649
+ usable = 0
1650
+ pathway = 0
1651
+ for model in models:
1652
+ entry = model_runtime_compatibility(model).get(target, {})
1653
+ status = str(entry.get("status") or "unknown").lower() if isinstance(entry, dict) else "unknown"
1654
+ statuses[status] = statuses.get(status, 0) + 1
1655
+ if status in _DEPLOYMENT_USABLE_STATUSES:
1656
+ usable += 1
1657
+ if status in _DEPLOYMENT_PATHWAY_STATUSES:
1658
+ pathway += 1
1659
+ summary[target] = {
1660
+ "label": label,
1661
+ "usable": usable,
1662
+ "pathway": pathway,
1663
+ "statuses": dict(_top_counts(statuses, limit=max(1, len(statuses)))),
1664
+ "browse_command": (
1665
+ f"MaramaRoute compat --target {_deployment_cli_target(target)} "
1666
+ f"--status {_deployment_cli_status(target)}"
1667
+ ),
1668
+ "picker_command": f"/{_deployment_cli_target(target)}",
1669
+ }
1670
+ return summary
1671
+
1672
+
1673
+ def _deployment_cli_target(target: str) -> str:
1674
+ if target == "nvidia_nim":
1675
+ return "nim"
1676
+ if target == "nvidia_nemo":
1677
+ return "nemo"
1678
+ return target
1679
+
1680
+
1681
+ def _deployment_cli_status(target: str) -> str:
1682
+ if target == "nvidia_nemo":
1683
+ return "pathway"
1684
+ return "usable"
1685
+
1686
+
1687
+ def _format_deployment_counts(deployment: dict[str, Any]) -> list[str]:
1688
+ lines: list[str] = []
1689
+ for target in ("vllm", "nvidia_nim", "nvidia_nemo"):
1690
+ entry = deployment.get(target, {})
1691
+ label = str(entry.get("label") or target)
1692
+ statuses = entry.get("statuses") if isinstance(entry.get("statuses"), dict) else {}
1693
+ status_text = _format_counts(statuses)
1694
+ if target == "nvidia_nemo":
1695
+ lines.append(f"{label}: direct {entry.get('usable', 0)}, pathway {entry.get('pathway', 0)} ({status_text})")
1696
+ else:
1697
+ lines.append(f"{label}: usable {entry.get('usable', 0)} ({status_text})")
1698
+ return lines
1699
+
1700
+
1701
  def _is_transformers_text_generation(model: Any) -> bool:
1702
  runtime = model.runtime.lower()
1703
  if "transformers" not in runtime or "multimodal" in runtime:
 
1768
  query: str,
1769
  include_all: bool,
1770
  hardware_only: bool,
1771
+ compatibility_target: str,
1772
  offset: int,
1773
  shown: int,
1774
  hardware: dict[str, Any] | None,
1775
  ) -> None:
1776
  total = len(models)
1777
  runnable = sum(1 for model in models if _is_chat_runnable(model))
1778
+ if compatibility_target:
1779
+ scope = f"{_DEPLOYMENT_TARGET_LABELS.get(compatibility_target, compatibility_target)} deployment-path models"
1780
+ elif hardware_only:
1781
  scope = "hardware-suitable local GGUF chat models"
1782
  else:
1783
  scope = "all AbteeXAILab HF registry entries" if include_all else "recommended local GGUF chat models"
 
1791
  print("Use /next for more results.")
1792
  if offset > 0:
1793
  print("Use /prev for previous results.")
1794
+ if compatibility_target:
1795
+ print("Use /vllm, /nim, /nemo, /all, or /models to change category.")
1796
+ elif not include_all and not hardware_only:
1797
+ print("Use /hardware for machine-suitable models, /all, /vllm, /nim, /nemo, or /help.")
1798
  else:
1799
+ print("Use /models to return to recommended chat models, /family <name>, /vllm, /nim, /nemo, or /help.")
1800
 
1801
 
1802
  def _print_model_picker_menu(models: tuple[Any, ...], cache_dir: Path | None) -> None:
 
1812
  print(" 4. Browse local GGUF chat models")
1813
  print(" 5. Browse full registry")
1814
  print(" 6. Show pulled local models")
1815
+ print(" 7. Browse vLLM deployment-path models")
1816
+ print(" 8. Browse NVIDIA NIM deployment-path models")
1817
+ print(" 9. Browse NVIDIA NeMo/NEM deployment-path models")
1818
 
1819
 
1820
  def _print_model_picker_help() -> None:
 
1826
  " /recommended show recommended local chat models",
1827
  " /models browse local GGUF chat-capable models",
1828
  " /all browse every bundled AbteeXAILab registry entry",
1829
+ " /vllm browse vLLM supported/candidate/experimental models",
1830
+ " /nim browse NVIDIA NIM supported/candidate/experimental models",
1831
+ " /nemo browse NVIDIA NeMo candidates and conversion paths",
1832
+ " /nem alias for /nemo",
1833
  " /search <text> search model id, repo, family, or tags",
1834
  " /family <name> filter by family or tag",
1835
+ " /categories show category/family/runtime/tag/deployment counts",
1836
  " /families alias for /categories",
1837
  " /next next page of results",
1838
  " /prev previous page of results",
 
1846
 
1847
  def _print_model_categories(models: tuple[Any, ...]) -> None:
1848
  _print_category_summary(_category_summary(models, limit=18))
1849
+ print("Type a family/tag/search term, or use /vllm, /nim, /nemo, /family qwen, /all, /runnable.")
1850
 
1851
 
1852
  def _category_summary(models: tuple[Any, ...], *, limit: int) -> dict[str, Any]:
 
1874
  "tags": dict(_top_counts(tags, limit=safe_limit)),
1875
  "modalities": dict(_top_counts(modalities, limit=safe_limit)),
1876
  "capabilities": dict(_top_counts(capabilities, limit=safe_limit)),
1877
+ "deployment_compatibility": _deployment_summary(models),
1878
  "commands": {
1879
  "browse_recommended": "MaramaRoute chat",
1880
  "browse_all": "MaramaRoute catalog",
 
1882
  "filter_family": "MaramaRoute catalog --family qwen",
1883
  "pull_family": "MaramaRoute pull --family qwen --limit 3 --dry-run",
1884
  "compatibility": "MaramaRoute compat",
1885
+ "browse_vllm": "MaramaRoute compat --target vllm --status usable",
1886
+ "browse_nim": "MaramaRoute compat --target nim --status usable",
1887
+ "browse_nem_nemo": "MaramaRoute compat --target nemo --status pathway",
1888
  },
1889
  }
1890
 
 
1898
  print(f"Runtimes: {_format_counts(summary['runtimes'])}")
1899
  print(f"Modalities: {_format_counts(summary['modalities'])}")
1900
  print(f"Tags: {_format_counts(summary['tags'])}")
1901
+ print("Deployment compatibility:")
1902
+ for line in _format_deployment_counts(summary.get("deployment_compatibility", {})):
1903
+ print(f" {line}")
1904
+ print(
1905
+ "Next: MaramaRoute chat | MaramaRoute compat --target vllm --status usable | "
1906
+ "MaramaRoute compat --target nemo --status pathway",
1907
+ )
1908
 
1909
 
1910
  def _format_counts(counts: dict[str, int]) -> str:
 
2170
  compat.add_argument("model", nargs="?", help="Optional model id, repo id, or unique search fragment.")
2171
  compat.add_argument("--registry", type=Path, default=None, help="MaramaRoute model registry JSON.")
2172
  compat.add_argument("--target", default="", help="Runtime target: vllm, nim, nem, nemo, llama-cpp, or all.")
2173
+ compat.add_argument(
2174
+ "--status",
2175
+ default="",
2176
+ help="Filter by status such as candidate, experimental, unsupported, usable, or pathway.",
2177
+ )
2178
  compat.add_argument("--limit", type=int, default=0, help="Maximum rows; 0 means all models.")
2179
  compat.add_argument("--format", choices=["json", "table"], default="table")
2180
  compat.set_defaults(handler=_compat)
 
2182
  categories = subparsers.add_parser(
2183
  "categories",
2184
  aliases=["families"],
2185
+ help="Show model families, runtimes, tags, modalities, local capability, and deployment categories.",
2186
  )
2187
  categories.add_argument("--registry", type=Path, default=None, help="MaramaRoute model registry JSON.")
2188
  categories.add_argument("--limit", type=int, default=18)
marama_route/compat.py CHANGED
@@ -6,6 +6,15 @@ from typing import Any
6
  from .registry import ModelEndpoint
7
 
8
  COMPATIBILITY_TARGETS = ("llama_cpp", "vllm", "nvidia_nim", "nvidia_nemo")
 
 
 
 
 
 
 
 
 
9
 
10
  _TASK_TAGS = {
11
  "asr",
@@ -104,12 +113,12 @@ def build_compatibility_matrix(
104
  summary[name][str(compatibility[name]["status"])] += 1
105
  if target:
106
  entry = compatibility[target]
107
- if wanted_status and str(entry["status"]).lower() != wanted_status:
108
  continue
109
  rows.append(_compatibility_row(model, {target: entry}))
110
  else:
111
  if wanted_status and not any(
112
- str(entry["status"]).lower() == wanted_status for entry in compatibility.values()
113
  ):
114
  continue
115
  rows.append(_compatibility_row(model, compatibility))
@@ -294,6 +303,15 @@ def _entry(status: str, reason: str, *, commands: list[str] | None = None) -> di
294
  return payload
295
 
296
 
 
 
 
 
 
 
 
 
 
297
  def _normalize_target(target: str) -> str:
298
  value = target.strip().lower().replace("-", "_")
299
  aliases = {
@@ -303,7 +321,7 @@ def _normalize_target(target: str) -> str:
303
  "llamacpp": "llama_cpp",
304
  "nim": "nvidia_nim",
305
  "nvidia_nim": "nvidia_nim",
306
- "nem": "nvidia_nim",
307
  "nemo": "nvidia_nemo",
308
  "nvidia_nemo": "nvidia_nemo",
309
  }
 
6
  from .registry import ModelEndpoint
7
 
8
  COMPATIBILITY_TARGETS = ("llama_cpp", "vllm", "nvidia_nim", "nvidia_nemo")
9
+ _USABLE_STATUSES = {"supported", "candidate", "experimental"}
10
+ _PATHWAY_STATUSES = _USABLE_STATUSES | {"convert_required"}
11
+ _STATUS_GROUPS = {
12
+ "usable": _USABLE_STATUSES,
13
+ "compatible": _USABLE_STATUSES,
14
+ "pathway": _PATHWAY_STATUSES,
15
+ "deployment_path": _PATHWAY_STATUSES,
16
+ "deployment-path": _PATHWAY_STATUSES,
17
+ }
18
 
19
  _TASK_TAGS = {
20
  "asr",
 
113
  summary[name][str(compatibility[name]["status"])] += 1
114
  if target:
115
  entry = compatibility[target]
116
+ if wanted_status and not _status_matches(str(entry["status"]), wanted_status):
117
  continue
118
  rows.append(_compatibility_row(model, {target: entry}))
119
  else:
120
  if wanted_status and not any(
121
+ _status_matches(str(entry["status"]), wanted_status) for entry in compatibility.values()
122
  ):
123
  continue
124
  rows.append(_compatibility_row(model, compatibility))
 
303
  return payload
304
 
305
 
306
+ def _status_matches(actual: str, wanted: str) -> bool:
307
+ actual_value = actual.strip().lower()
308
+ wanted_value = wanted.strip().lower()
309
+ status_group = _STATUS_GROUPS.get(wanted_value)
310
+ if status_group is not None:
311
+ return actual_value in status_group
312
+ return actual_value == wanted_value
313
+
314
+
315
  def _normalize_target(target: str) -> str:
316
  value = target.strip().lower().replace("-", "_")
317
  aliases = {
 
321
  "llamacpp": "llama_cpp",
322
  "nim": "nvidia_nim",
323
  "nvidia_nim": "nvidia_nim",
324
+ "nem": "nvidia_nemo",
325
  "nemo": "nvidia_nemo",
326
  "nvidia_nemo": "nvidia_nemo",
327
  }
pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
 
5
  [project]
6
  name = "lumynax-marama-route"
7
- version = "0.7.11"
8
  description = "LumynaX MaramaRoute: conversational AbteeX AI Labs model CLI, downloader, and local runtime for LumynaX releases."
9
  readme = "README.md"
10
  requires-python = ">=3.11"
 
4
 
5
  [project]
6
  name = "lumynax-marama-route"
7
+ version = "0.7.12"
8
  description = "LumynaX MaramaRoute: conversational AbteeX AI Labs model CLI, downloader, and local runtime for LumynaX releases."
9
  readme = "README.md"
10
  requires-python = ">=3.11"