Coverage for src/lilbee/providers/fleet/contract.py: 100%

26 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-08-14 11:46 +0000

1"""Decides whether a running engine can serve a lilbee's configuration. 

2 

3The contract is the per-role models plus the engine build pin. Planner-derived 

4values (ctx, slots) are accepted from the running engine, never recomputed: 

5they vary legitimately with GPU occupancy at plan time. The one exception is 

6``chat_ctx_covers``: a live chat window smaller than what this process needs 

7cannot be adopted, since no prompt fit can grow it. 

8""" 

9 

10from __future__ import annotations 

11 

12from typing import TYPE_CHECKING 

13 

14from lilbee.providers.fleet.launch import InstanceLaunch 

15from lilbee.providers.roles import WorkerRole 

16 

17if TYPE_CHECKING: 

18 from collections.abc import Iterable 

19 

20 from lilbee.providers.fleet.swap_manager import SwapState 

21 

22 

23def decoded_launches(state: SwapState) -> list[InstanceLaunch] | None: 

24 """The engine's recorded launches, or ``None`` when the contract is undecodable. 

25 

26 The single decode site. Callers previously re-decoded launches bare, relying on 

27 a preceding contract_matches call to have proven decodability, so reordering or 

28 dropping that guard turned a non-match into an unhandled exception in the bind 

29 ladder. Returning ``None`` makes "undecodable" a value every caller must handle. 

30 """ 

31 try: 

32 return [InstanceLaunch.from_state(item) for item in state.launches] 

33 except (KeyError, TypeError, ValueError): 

34 return None 

35 

36 

37def served_pairs(state: SwapState) -> set[tuple[WorkerRole, str]] | None: 

38 """The (role, model) pairs the engine behind *state* serves, or ``None``.""" 

39 launches = decoded_launches(state) 

40 return None if launches is None else {(launch.role, launch.model) for launch in launches} 

41 

42 

43def chat_ctx_covers(launches: Iterable[InstanceLaunch], demanded_ctx: int) -> bool: 

44 """Whether the engine's per-slot chat window serves *demanded_ctx* tokens. 

45 

46 ``launches`` are the running engine's recorded launches. A zero demand, no 

47 chat launch, or a record without a positive chat ctx never refuses: derived 

48 values are adopted from the running engine. A window below the demand still 

49 covers when the record's ``built_ctx_target`` reaches the demand: the same 

50 planner aimed at least as high and achieved this window, so replacing the 

51 engine would rebuild the same window in a loop. A refusal sends the ladder 

52 to its replace-or-overflow decision. 

53 """ 

54 chat = [launch for launch in launches if launch.role is WorkerRole.CHAT and launch.ctx > 0] 

55 live = min((launch.ctx for launch in chat), default=0) 

56 if demanded_ctx <= 0 or live <= 0 or demanded_ctx <= live: 

57 return True 

58 built_target = min((launch.built_ctx_target for launch in chat), default=0) 

59 return built_target > 0 and demanded_ctx <= built_target 

60 

61 

62def contract_matches(state: SwapState, wanted: Iterable[tuple[WorkerRole, str]], pin: str) -> bool: 

63 """Whether the engine behind *state* serves every wanted (role, model) pair. 

64 

65 The engine may serve more roles than asked; the engine build pin must 

66 equal *pin*, and an empty or undecodable served contract never matches. 

67 """ 

68 if state.engine_pin != pin: 

69 return False 

70 served = served_pairs(state) 

71 if not served: 

72 return False 

73 return all(pair in served for pair in wanted)