coderouter-cli 2.9.2__py3-none-any.whl → 2.9.4__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.
@@ -1460,6 +1460,49 @@ class LauncherOptionProfile(BaseModel):
1460
1460
  )
1461
1461
 
1462
1462
 
1463
+ class LauncherBenchConfig(BaseModel):
1464
+ """The ``launcher.bench:`` block — defaults for the bench sweep feature.
1465
+
1466
+ 設計 §4.1。デバイス構成スイープ(起動→readiness→外部ベンチ→停止→次)の
1467
+ 既定値を providers.yaml から供給する。未設定(``LauncherConfig.bench`` が
1468
+ None)ならスイープ UI はハードコード既定を使う(完全後方互換)。すべての
1469
+ フィールドに ``default`` があるので、既存 YAML は無改変で通過する。
1470
+ """
1471
+
1472
+ model_config = ConfigDict(extra="forbid")
1473
+
1474
+ command_template: str = Field(
1475
+ default="llmbench run --model local-openai --runs {runs}",
1476
+ description=(
1477
+ "外部ベンチコマンドのテンプレ。``{port}`` ``{config}`` "
1478
+ "``{base_url}`` ``{results_dir}`` ``{runs}`` を単純置換で展開して "
1479
+ "argv 化する(``str.format`` ではないので JSON 波括弧で誤爆しない)。"
1480
+ ),
1481
+ )
1482
+ runs: int = Field(
1483
+ default=5,
1484
+ ge=1,
1485
+ le=1000,
1486
+ description="1 構成あたりのベンチ実行回数。``{runs}`` に展開される。",
1487
+ )
1488
+ results_dir: str | None = Field(
1489
+ default=None,
1490
+ description=(
1491
+ "llmbench の results/ ディレクトリ。相対はサーバ CWD 基準。"
1492
+ "設定時のみスイープ結果 JSON を読み比較サマリを付与する。"
1493
+ ),
1494
+ )
1495
+ readiness_timeout_s: float = Field(
1496
+ default=300.0,
1497
+ ge=5.0,
1498
+ le=3600.0,
1499
+ description=(
1500
+ "スイープの各構成でサーバが ready になるのを待つ最大秒数。"
1501
+ "大きな GGUF ロードを考慮した既定 5 分。"
1502
+ ),
1503
+ )
1504
+
1505
+
1463
1506
  class SwapModelSpec(BaseModel):
1464
1507
  """One entry in ``launcher.swap.models`` (docs/designs/launcher-model-swap.md).
1465
1508
 
@@ -1518,10 +1561,25 @@ class SwapModelSpec(BaseModel):
1518
1561
  le=65535,
1519
1562
  description=(
1520
1563
  "Fixed port (recommended — §10 Q2). When unset, the swap "
1521
- "manager picks an OS-assigned ephemeral port and retries "
1522
- "once on a different port if the backend fails to become "
1523
- "ready. Best-effort only — no strong TOCTOU guarantee "
1524
- "(§6.6 known-trap #4)."
1564
+ "manager picks an OS-assigned ephemeral port and retries, "
1565
+ "each time on a freshly picked port, up to "
1566
+ "``LauncherSwapConfig.port_retry_attempts`` additional "
1567
+ "times if the backend fails to become ready. Best-effort "
1568
+ "only — no strong TOCTOU guarantee (§6.6 known-trap #4)."
1569
+ ),
1570
+ )
1571
+ ttl_seconds: float | None = Field(
1572
+ default=None,
1573
+ ge=0.0,
1574
+ description=(
1575
+ "[Unreleased] Per-model override of "
1576
+ "``LauncherSwapConfig.ttl_seconds``. ``None`` (default) = "
1577
+ "use the global value. ``0`` = unload as soon as the last "
1578
+ "in-flight lease for THIS model releases — same meaning as "
1579
+ "the global field's ``0``, just scoped to one catalog "
1580
+ "entry. Lets a large/expensive model unload sooner (or "
1581
+ "stay resident longer) than the rest of the catalog "
1582
+ "without changing the global default."
1525
1583
  ),
1526
1584
  )
1527
1585
  option_profile: str | None = Field(
@@ -1611,8 +1669,10 @@ class LauncherSwapConfig(BaseModel):
1611
1669
  "Seconds of no in-flight requests after which an idle swap "
1612
1670
  "process is auto-stopped. None = TTL disabled (runs until "
1613
1671
  "explicitly stopped). 0 = unload as soon as the last "
1614
- "in-flight lease releases. §10 Q1: one GLOBAL value for "
1615
- "Phase 1 — no per-model override yet."
1672
+ "in-flight lease releases. §10 Q1: this is the GLOBAL "
1673
+ "default; a catalog entry's ``SwapModelSpec.ttl_seconds`` "
1674
+ "overrides it for that one model when set "
1675
+ "([Unreleased] per-model TTL override)."
1616
1676
  ),
1617
1677
  )
1618
1678
  readiness_timeout_s: float = Field(
@@ -1631,6 +1691,24 @@ class LauncherSwapConfig(BaseModel):
1631
1691
  le=600.0,
1632
1692
  description="How often the TTL sweeper background task scans for idle processes.",
1633
1693
  )
1694
+ port_retry_attempts: int = Field(
1695
+ default=2,
1696
+ ge=0,
1697
+ le=5,
1698
+ description=(
1699
+ "[Unreleased] Number of ADDITIONAL spawn attempts (each on a "
1700
+ "freshly picked ephemeral port) after the first, used only "
1701
+ "when a catalog entry's ``port`` is unset and the previous "
1702
+ "attempt fails to become ready. 0 = no retry. Ignored when "
1703
+ "``port`` is set — a fixed port never retries (a second "
1704
+ "attempt would just collide on the same port again). This "
1705
+ "does not close the pick-then-bind TOCTOU window (see "
1706
+ "``coderouter.launcher_swap._pick_ephemeral_port``); it only "
1707
+ "bounds how many times the swap manager re-rolls the dice. "
1708
+ "A fixed ``port`` remains the recommended way to eliminate "
1709
+ "the race entirely (§10 Q2)."
1710
+ ),
1711
+ )
1634
1712
  inject_auto_router_rules: bool = Field(
1635
1713
  default=True,
1636
1714
  description=(
@@ -1828,6 +1906,13 @@ class LauncherConfig(BaseModel):
1828
1906
  "behavior."
1829
1907
  ),
1830
1908
  )
1909
+ bench: LauncherBenchConfig | None = Field(
1910
+ default=None,
1911
+ description=(
1912
+ "デバイス構成ベンチスイープ(設計 §4)の既定値。None(既定)なら "
1913
+ "スイープ UI はハードコード既定を使う=完全後方互換。"
1914
+ ),
1915
+ )
1831
1916
 
1832
1917
  @model_validator(mode="after")
1833
1918
  def _check_auto_restart_backoff_ordered(self) -> LauncherConfig: