lmcache-cli 0.4.6.dev0__py3-none-any.whl → 0.4.8.dev24__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.
Files changed (253) hide show
  1. lmcache/__init__.py +32 -21
  2. lmcache/_version.py +3 -3
  3. lmcache/banner.py +119 -0
  4. lmcache/cli/commands/__init__.py +31 -25
  5. lmcache/cli/commands/bench/__init__.py +16 -605
  6. lmcache/cli/commands/bench/engine_bench/command.py +599 -0
  7. lmcache/cli/commands/bench/engine_bench/config.py +3 -3
  8. lmcache/cli/commands/bench/engine_bench/interactive/state.py +2 -2
  9. lmcache/cli/commands/bench/engine_bench/workloads/base.py +13 -3
  10. lmcache/cli/commands/bench/engine_bench/workloads/long_doc_permutator.py +0 -20
  11. lmcache/cli/commands/bench/l2_adapter_bench/__init__.py +2 -0
  12. lmcache/cli/commands/bench/l2_adapter_bench/command.py +630 -0
  13. lmcache/cli/commands/bench/l2_adapter_bench/data.py +195 -0
  14. lmcache/cli/commands/bench/l2_adapter_bench/result.py +174 -0
  15. lmcache/cli/commands/bench/l2_adapter_bench/runner.py +319 -0
  16. lmcache/cli/commands/bench/server_bench/__init__.py +2 -0
  17. lmcache/cli/commands/bench/server_bench/command.py +719 -0
  18. lmcache/cli/commands/bench/server_bench/helpers.py +1125 -0
  19. lmcache/cli/commands/coordinator.py +155 -0
  20. lmcache/cli/commands/describe.py +47 -24
  21. lmcache/cli/commands/query/__init__.py +35 -114
  22. lmcache/cli/commands/query/engine_command.py +130 -0
  23. lmcache/cli/commands/query/kvcache_command.py +46 -0
  24. lmcache/cli/commands/quota/__init__.py +91 -0
  25. lmcache/cli/commands/quota/delete_command.py +77 -0
  26. lmcache/cli/commands/quota/get_command.py +80 -0
  27. lmcache/cli/commands/quota/helpers.py +78 -0
  28. lmcache/cli/commands/quota/list_command.py +76 -0
  29. lmcache/cli/commands/quota/set_command.py +90 -0
  30. lmcache/cli/commands/server.py +11 -3
  31. lmcache/cli/commands/trace/__init__.py +35 -404
  32. lmcache/cli/commands/trace/info_command.py +77 -0
  33. lmcache/cli/commands/trace/replay_command.py +340 -0
  34. lmcache/cli/main.py +2 -0
  35. lmcache/integration/base_service_factory.py +6 -2
  36. lmcache/integration/sglang/multi_process_adapter.py +544 -0
  37. lmcache/integration/sglang/sglang_adapter.py +64 -26
  38. lmcache/integration/sglang/utils.py +12 -22
  39. lmcache/integration/tensorrt_llm/tensorrt_mp_adapter.py +8 -7
  40. lmcache/integration/vllm/kv_cache_group_edits.py +402 -0
  41. lmcache/integration/vllm/kv_cache_groups.py +190 -0
  42. lmcache/integration/vllm/lmcache_mp_connector.py +332 -250
  43. lmcache/integration/vllm/lmcache_mp_connector_0180.py +8 -1
  44. lmcache/integration/vllm/lmcache_mp_connector_0201.py +7 -1
  45. lmcache/integration/vllm/vllm_multi_process_adapter.py +511 -138
  46. lmcache/integration/vllm/vllm_v1_adapter.py +76 -6
  47. lmcache/lmcache_frontend/__init__.py +2 -0
  48. lmcache/lmcache_frontend/app.py +1036 -0
  49. lmcache/lmcache_frontend/config.json +1 -0
  50. lmcache/lmcache_frontend/heartbeat.py +233 -0
  51. lmcache/lmcache_frontend/lmcache_mp_plugin/__init__.py +1 -0
  52. lmcache/lmcache_frontend/lmcache_mp_plugin/lmcache_mp_frontend_plugin.py +176 -0
  53. lmcache/lmcache_frontend/run_mp_server_with_frontend.sh +21 -0
  54. lmcache/lmcache_frontend/static/css/style.css +190 -0
  55. lmcache/lmcache_frontend/static/img/logo.png +0 -0
  56. lmcache/lmcache_frontend/static/index.html +239 -0
  57. lmcache/lmcache_frontend/static/js/app.js +1189 -0
  58. lmcache/native_storage_ops.pyi +61 -2
  59. lmcache/observability.py +160 -98
  60. lmcache/{non_cuda_equivalents.py → python_ops_fallback.py} +1224 -68
  61. lmcache/tools/controller_benchmark/handlers/__init__.py +11 -26
  62. lmcache/tools/simple_discover_service.py +118 -0
  63. lmcache/utils.py +66 -1
  64. lmcache/v1/cache_controller/controllers/kv_controller.py +1 -1
  65. lmcache/v1/cache_controller/executor.py +2 -2
  66. lmcache/v1/cache_engine.py +94 -12
  67. lmcache/v1/check/check_mode_test_l2_adapter.py +2 -2
  68. lmcache/v1/compute/attention/flash_attn.py +13 -4
  69. lmcache/v1/compute/attention/utils.py +20 -0
  70. lmcache/v1/config.py +82 -1
  71. lmcache/v1/distributed/api.py +71 -42
  72. lmcache/v1/distributed/config.py +88 -0
  73. lmcache/v1/distributed/eviction.py +1 -1
  74. lmcache/v1/distributed/internal_api.py +32 -1
  75. lmcache/v1/distributed/l1_manager.py +14 -2
  76. lmcache/v1/distributed/l2_adapters/aerospike_l2_adapter.py +239 -0
  77. lmcache/v1/distributed/l2_adapters/base.py +9 -30
  78. lmcache/v1/distributed/l2_adapters/dax_l2_adapter.py +1073 -77
  79. lmcache/v1/distributed/l2_adapters/fs_l2_adapter.py +25 -28
  80. lmcache/v1/distributed/l2_adapters/hfbucket_l2_adapter.py +902 -0
  81. lmcache/v1/distributed/l2_adapters/mock_l2_adapter.py +7 -16
  82. lmcache/v1/distributed/l2_adapters/native_connector_l2_adapter.py +10 -10
  83. lmcache/v1/distributed/l2_adapters/nixl_store_dynamic_l2_adapter.py +11 -5
  84. lmcache/v1/distributed/l2_adapters/nixl_store_l2_adapter.py +12 -25
  85. lmcache/v1/distributed/l2_adapters/raw_block_l2_adapter.py +37 -6
  86. lmcache/v1/distributed/l2_adapters/reconfiguration.py +64 -0
  87. lmcache/v1/distributed/l2_adapters/s3_l2_adapter.py +16 -12
  88. lmcache/v1/distributed/l2_adapters/serde_wrapper.py +16 -25
  89. lmcache/v1/distributed/memory_manager/__init__.py +25 -0
  90. lmcache/v1/distributed/memory_manager/gds_l1_memory_manager.py +158 -0
  91. lmcache/v1/distributed/memory_manager/l1_manager_protocol.py +50 -0
  92. lmcache/v1/distributed/{memory_manager.py → memory_manager/l1_memory_manager.py} +37 -0
  93. lmcache/v1/distributed/serde/__init__.py +16 -0
  94. lmcache/v1/distributed/serde/asym_k16_v8.py +537 -0
  95. lmcache/v1/distributed/serde/async_processor.py +16 -1
  96. lmcache/v1/distributed/serde/multi.py +293 -0
  97. lmcache/v1/distributed/serde/utils.py +2 -1
  98. lmcache/v1/distributed/storage_controllers/eviction_controller.py +14 -0
  99. lmcache/v1/distributed/storage_controllers/prefetch_controller.py +128 -118
  100. lmcache/v1/distributed/storage_controllers/store_controller.py +11 -20
  101. lmcache/v1/distributed/storage_manager.py +267 -34
  102. lmcache/v1/gpu_connector/__init__.py +152 -39
  103. lmcache/v1/gpu_connector/_cufile_async.py +384 -0
  104. lmcache/v1/gpu_connector/gds_context.py +408 -0
  105. lmcache/v1/gpu_connector/gpu_connectors.py +49 -41
  106. lmcache/v1/gpu_connector/gpu_ops.py +8 -1
  107. lmcache/v1/gpu_connector/hpu_connector.py +22 -13
  108. lmcache/v1/gpu_connector/musa_connectors.py +825 -0
  109. lmcache/v1/gpu_connector/musa_native.py +218 -0
  110. lmcache/v1/gpu_connector/utils.py +518 -284
  111. lmcache/v1/gpu_connector/xpu_connectors.py +1525 -647
  112. lmcache/v1/health_monitor/base.py +21 -40
  113. lmcache/v1/internal_api_server/api_server.py +11 -8
  114. lmcache/v1/internal_api_server/common/loglevel_api.py +5 -5
  115. lmcache/v1/internal_api_server/common/run_script_api.py +16 -6
  116. lmcache/v1/internal_api_server/vllm/cache_api.py +5 -3
  117. lmcache/v1/kv_codec/__init__.py +63 -0
  118. lmcache/v1/kv_codec/asym_k16_v8.py +473 -0
  119. lmcache/v1/kv_codec/encoded_kv.py +403 -0
  120. lmcache/v1/kv_codec/errors.py +39 -0
  121. lmcache/v1/kv_layer_groups.py +447 -207
  122. lmcache/v1/lookup_client/chunk_statistics_lookup_client.py +20 -11
  123. lmcache/v1/lookup_client/factory.py +1 -0
  124. lmcache/v1/lookup_client/record_strategies/__init__.py +10 -18
  125. lmcache/v1/memory_management.py +358 -126
  126. lmcache/v1/metadata.py +3 -3
  127. lmcache/v1/mp_coordinator/__init__.py +17 -0
  128. lmcache/v1/mp_coordinator/__main__.py +28 -0
  129. lmcache/v1/mp_coordinator/app.py +134 -0
  130. lmcache/v1/mp_coordinator/blend_client.py +266 -0
  131. lmcache/v1/mp_coordinator/blend_directory.py +236 -0
  132. lmcache/v1/mp_coordinator/config.py +120 -0
  133. lmcache/v1/mp_coordinator/http_apis/__init__.py +6 -0
  134. lmcache/v1/mp_coordinator/http_apis/blend_directory_api.py +103 -0
  135. lmcache/v1/mp_coordinator/http_apis/health_api.py +20 -0
  136. lmcache/v1/mp_coordinator/http_apis/instances_api.py +136 -0
  137. lmcache/v1/mp_coordinator/http_apis/l2_api.py +255 -0
  138. lmcache/v1/mp_coordinator/l2/__init__.py +1 -0
  139. lmcache/v1/mp_coordinator/l2/event_listener.py +150 -0
  140. lmcache/v1/mp_coordinator/l2/eviction_manager.py +161 -0
  141. lmcache/v1/mp_coordinator/l2/usage_manager.py +121 -0
  142. lmcache/v1/mp_coordinator/registrar.py +130 -0
  143. lmcache/v1/mp_coordinator/registry.py +161 -0
  144. lmcache/v1/mp_coordinator/schemas.py +286 -0
  145. lmcache/v1/mp_observability/README.md +2 -3
  146. lmcache/v1/mp_observability/config.py +9 -22
  147. lmcache/v1/mp_observability/event.py +19 -0
  148. lmcache/v1/mp_observability/event_bus.py +22 -0
  149. lmcache/v1/mp_observability/otel_init.py +1 -1
  150. lmcache/v1/mp_observability/subscribers/__init__.py +0 -2
  151. lmcache/v1/mp_observability/subscribers/logging/l2.py +7 -0
  152. lmcache/v1/mp_observability/subscribers/metrics/__init__.py +0 -2
  153. lmcache/v1/mp_observability/subscribers/metrics/cb_server.py +14 -0
  154. lmcache/v1/mp_observability/subscribers/metrics/event_bus.py +1 -19
  155. lmcache/v1/mp_observability/subscribers/metrics/l0_l1_throughput.py +4 -4
  156. lmcache/v1/mp_observability/subscribers/metrics/l0_lifecycle.py +6 -6
  157. lmcache/v1/mp_observability/subscribers/metrics/l1.py +19 -12
  158. lmcache/v1/mp_observability/subscribers/metrics/l1_failures.py +2 -0
  159. lmcache/v1/mp_observability/subscribers/metrics/l1_lifecycle.py +8 -8
  160. lmcache/v1/mp_observability/subscribers/metrics/l2.py +94 -63
  161. lmcache/v1/mp_observability/subscribers/metrics/l2_failures.py +1 -0
  162. lmcache/v1/mp_observability/subscribers/metrics/l2_throughput.py +23 -25
  163. lmcache/v1/mp_observability/subscribers/metrics/lookup.py +4 -4
  164. lmcache/v1/mp_observability/subscribers/metrics/sm_lifecycle.py +2 -2
  165. lmcache/v1/mp_observability/subscribers/metrics/utils.py +28 -0
  166. lmcache/v1/mp_observability/subscribers/tracing/cb_server.py +44 -5
  167. lmcache/v1/mp_observability/trace/codecs.py +38 -3
  168. lmcache/v1/multiprocess/config.py +241 -5
  169. lmcache/v1/multiprocess/custom_types.py +81 -34
  170. lmcache/v1/multiprocess/engine_context.py +247 -0
  171. lmcache/v1/multiprocess/engine_module.py +65 -0
  172. lmcache/v1/multiprocess/group_view.py +239 -0
  173. lmcache/v1/multiprocess/http_apis/cache_api.py +14 -14
  174. lmcache/v1/multiprocess/http_apis/common_api.py +1 -1
  175. lmcache/v1/multiprocess/http_apis/reconfigure_api.py +374 -0
  176. lmcache/v1/multiprocess/http_server.py +85 -6
  177. lmcache/v1/multiprocess/modules/__init__.py +1 -0
  178. lmcache/v1/multiprocess/{blend_server_v2.py → modules/blend.py} +283 -445
  179. lmcache/v1/multiprocess/modules/blend_v3.py +1522 -0
  180. lmcache/v1/multiprocess/modules/engine_driven_transfer.py +444 -0
  181. lmcache/v1/multiprocess/modules/lmcache_driven_transfer.py +968 -0
  182. lmcache/v1/multiprocess/modules/lookup.py +467 -0
  183. lmcache/v1/multiprocess/modules/management.py +129 -0
  184. lmcache/v1/multiprocess/modules/server_transfer.py +440 -0
  185. lmcache/v1/multiprocess/mq.py +212 -76
  186. lmcache/v1/multiprocess/native_completion.py +150 -0
  187. lmcache/v1/multiprocess/posix_shm.py +273 -0
  188. lmcache/v1/multiprocess/protocol.py +2 -2
  189. lmcache/v1/multiprocess/protocols/__init__.py +2 -0
  190. lmcache/v1/multiprocess/protocols/base.py +12 -0
  191. lmcache/v1/multiprocess/protocols/blend.py +9 -9
  192. lmcache/v1/multiprocess/protocols/blend_v2.py +5 -5
  193. lmcache/v1/multiprocess/protocols/blend_v3.py +69 -0
  194. lmcache/v1/multiprocess/protocols/engine.py +99 -8
  195. lmcache/v1/multiprocess/server.py +230 -1106
  196. lmcache/v1/multiprocess/session.py +3 -2
  197. lmcache/v1/multiprocess/token_hasher.py +21 -12
  198. lmcache/v1/multiprocess/transfer_context/__init__.py +43 -0
  199. lmcache/v1/multiprocess/transfer_context/base.py +714 -0
  200. lmcache/v1/multiprocess/transfer_context/pickle.py +110 -0
  201. lmcache/v1/multiprocess/transfer_context/shm.py +218 -0
  202. lmcache/v1/multiprocess/transfer_context/worker_transfer.py +550 -0
  203. lmcache/v1/periodic_thread.py +5 -0
  204. lmcache/v1/pin_monitor.py +24 -10
  205. lmcache/v1/platform/__init__.py +50 -0
  206. lmcache/v1/platform/_registry.py +130 -0
  207. lmcache/v1/platform/base_cache_context.py +339 -0
  208. lmcache/v1/platform/cache_context.py +205 -0
  209. lmcache/v1/platform/cpu/__init__.py +35 -0
  210. lmcache/v1/platform/cpu/cache_context.py +443 -0
  211. lmcache/v1/platform/cpu/shm.py +292 -0
  212. lmcache/v1/platform/cpu/stub_cpu_device.py +338 -0
  213. lmcache/v1/platform/cuda/__init__.py +44 -0
  214. lmcache/v1/platform/cuda/cache_context.py +631 -0
  215. lmcache/v1/platform/event_notifier.py +17 -0
  216. lmcache/v1/storage_backend/__init__.py +24 -4
  217. lmcache/v1/storage_backend/abstract_backend.py +2 -2
  218. lmcache/v1/storage_backend/batched_message_sender.py +11 -7
  219. lmcache/v1/storage_backend/cache_policy/fifo.py +1 -1
  220. lmcache/v1/storage_backend/cache_policy/lfu.py +1 -1
  221. lmcache/v1/storage_backend/cache_policy/lru.py +1 -1
  222. lmcache/v1/storage_backend/cache_policy/mru.py +1 -1
  223. lmcache/v1/storage_backend/connector/__init__.py +13 -33
  224. lmcache/v1/storage_backend/connector/bigtable_adapter.py +30 -0
  225. lmcache/v1/storage_backend/connector/bigtable_config.py +136 -0
  226. lmcache/v1/storage_backend/connector/bigtable_connector.py +929 -0
  227. lmcache/v1/storage_backend/connector/bigtable_schema.py +57 -0
  228. lmcache/v1/storage_backend/connector/redis_adapter.py +20 -4
  229. lmcache/v1/storage_backend/dax/core.py +229 -0
  230. lmcache/v1/storage_backend/gds_backend.py +10 -5
  231. lmcache/v1/storage_backend/hipfile_shim.py +167 -0
  232. lmcache/v1/storage_backend/local_cpu_backend.py +75 -16
  233. lmcache/v1/storage_backend/local_disk_backend.py +2 -0
  234. lmcache/v1/storage_backend/native_clients/aerospike_client.py +74 -0
  235. lmcache/v1/storage_backend/nixl_storage_backend.py +671 -181
  236. lmcache/v1/storage_backend/pd_backend.py +1 -1
  237. lmcache/v1/storage_backend/plugins/rust_raw_block_backend.py +107 -8
  238. lmcache/v1/storage_backend/raw_block/core.py +505 -35
  239. lmcache/v1/storage_backend/raw_block/key_codec.py +11 -7
  240. lmcache/v1/storage_backend/remote_backend.py +12 -14
  241. lmcache/v1/storage_backend/storage_manager.py +65 -15
  242. lmcache/v1/token_database.py +30 -2
  243. lmcache/v1/utils/subclass_discovery.py +219 -0
  244. lmcache_cli-0.4.8.dev24.dist-info/METADATA +179 -0
  245. {lmcache_cli-0.4.6.dev0.dist-info → lmcache_cli-0.4.8.dev24.dist-info}/RECORD +249 -146
  246. lmcache/cli/commands/test_cache.py +0 -997
  247. lmcache/v1/mp_observability/subscribers/metrics/sm.py +0 -69
  248. lmcache/v1/multiprocess/gpu_context.py +0 -540
  249. lmcache_cli-0.4.6.dev0.dist-info/METADATA +0 -186
  250. {lmcache_cli-0.4.6.dev0.dist-info → lmcache_cli-0.4.8.dev24.dist-info}/WHEEL +0 -0
  251. {lmcache_cli-0.4.6.dev0.dist-info → lmcache_cli-0.4.8.dev24.dist-info}/entry_points.txt +0 -0
  252. {lmcache_cli-0.4.6.dev0.dist-info → lmcache_cli-0.4.8.dev24.dist-info}/licenses/LICENSE +0 -0
  253. {lmcache_cli-0.4.6.dev0.dist-info → lmcache_cli-0.4.8.dev24.dist-info}/top_level.txt +0 -0
lmcache/__init__.py CHANGED
@@ -4,6 +4,7 @@
4
4
  from typing import Any
5
5
  import importlib
6
6
  import sys
7
+ import types
7
8
 
8
9
  # First Party
9
10
  from lmcache.logging import init_logger
@@ -30,10 +31,8 @@ def _detect_device() -> tuple[Any, str]:
30
31
 
31
32
  Returns:
32
33
  tuple[Any, str]: A tuple of (torch_device_module, device_type_string),
33
- e.g. ``(torch.cuda, "cuda")`` or ``(torch.xpu, "xpu")``.
34
-
35
- Raises:
36
- RuntimeError: If no supported accelerator is found (checked CUDA, XPU, HPU).
34
+ e.g. ``(torch.cuda, "cuda")``, ``(torch.musa, "musa")``, or
35
+ ``(torch.xpu, "xpu")``.
37
36
  """
38
37
  try:
39
38
  # Third Party
@@ -41,18 +40,27 @@ def _detect_device() -> tuple[Any, str]:
41
40
  except ImportError:
42
41
  return None, "cpu" # fallback,CLI-only
43
42
 
44
- if hasattr(torch, "xpu") and torch.xpu.is_available():
43
+ if hasattr(torch, "musa") and torch.musa.is_available(): # type: ignore[attr-defined]
44
+ logger.info("MUSA device is available. Using MUSA for LMCache engine.")
45
+ return torch.musa, "musa" # type: ignore[attr-defined]
46
+ elif hasattr(torch, "xpu") and torch.xpu.is_available():
45
47
  return torch.xpu, "xpu"
46
48
  elif hasattr(torch, "hpu") and torch.hpu.is_available():
47
49
  return torch.hpu, "hpu"
48
- else:
49
- # Fallback: always return torch.cuda for backward compatibility
50
- # with existing tests and code paths that assume CUDA is the default.
50
+ elif torch.cuda.is_available():
51
51
  return torch.cuda, "cuda"
52
+ else:
53
+ # First Party
54
+ from lmcache.v1.platform.cpu.stub_cpu_device import StubCPUDevice
55
+
56
+ # Fallback: always return torch, cpu as stub
57
+ return StubCPUDevice("cpu"), "cpu"
52
58
 
53
59
 
54
60
  torch_dev, torch_device_type = _detect_device()
55
61
 
62
+ logger.info(" torch_dev=%s, torch_device_type=%s", torch_dev, torch_device_type)
63
+
56
64
 
57
65
  # --------------------------
58
66
  # Dynamic backend selection
@@ -61,10 +69,16 @@ def _get_backend() -> Any:
61
69
  """
62
70
  Try backends in order, first successful import wins.
63
71
  """
72
+ default_module = importlib.import_module("lmcache.python_ops_fallback")
64
73
  # Third Party
65
74
  import torch
66
75
 
67
76
  backend_candidates = [
77
+ (
78
+ "lmcache.xpu_ops",
79
+ "xpu_ops",
80
+ lambda: torch.xpu.is_available(),
81
+ ),
68
82
  (
69
83
  "lmcache.c_ops",
70
84
  "cuda_ops",
@@ -73,8 +87,6 @@ def _get_backend() -> Any:
73
87
  # should extend to more HWs..
74
88
  ]
75
89
 
76
- imported = False
77
- module = None
78
90
  for module_name, backend_name, predicate in backend_candidates:
79
91
  # 1 Check whether the backend is available before importing
80
92
  try:
@@ -93,21 +105,16 @@ def _get_backend() -> Any:
93
105
  continue
94
106
  # 2 Run availability check for the backend
95
107
  try:
96
- module = importlib.import_module(module_name)
108
+ backend_module = importlib.import_module(module_name)
109
+ merged_module = types.ModuleType("lmcache.c_ops")
110
+ merged_module.__dict__.update(default_module.__dict__)
111
+ merged_module.__dict__.update(backend_module.__dict__)
97
112
  logger.info("Using backend: %s", module_name)
98
- imported = True
99
- break
113
+ return merged_module
100
114
  except Exception as e:
101
115
  logger.warning("Failed to import backend %s: %s", module_name, e)
102
116
 
103
- if not imported:
104
- try:
105
- logger.warning("Fallback to python backend lmcache.non_cuda_equivalents")
106
- module = importlib.import_module("lmcache.non_cuda_equivalents")
107
- logger.info("Using backend: lmcache.non_cuda_equivalents")
108
- except ImportError as e:
109
- raise ImportError("No backend could be imported for lmcache.") from e
110
- return module
117
+ return default_module
111
118
 
112
119
 
113
120
  # --------------------------
@@ -115,6 +122,10 @@ def _get_backend() -> Any:
115
122
  # --------------------------
116
123
  try:
117
124
  _ops = _get_backend()
125
+ # override lmcache.c_ops with merged module,
126
+ # in which:
127
+ # python_ops_fallback as base,
128
+ # use backend implementation if exists
118
129
  sys.modules["lmcache.c_ops"] = _ops
119
130
  except (ImportError, ModuleNotFoundError):
120
131
  logger.debug("No compute backend loaded; CLI-only mode (torch/numba not installed)")
lmcache/_version.py CHANGED
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.4.6.dev0'
22
- __version_tuple__ = version_tuple = (0, 4, 6, 'dev0')
21
+ __version__ = version = '0.4.8.dev24'
22
+ __version_tuple__ = version_tuple = (0, 4, 8, 'dev24')
23
23
 
24
- __commit_id__ = commit_id = 'g168bbb976'
24
+ __commit_id__ = commit_id = 'gf52b174ca'
lmcache/banner.py ADDED
@@ -0,0 +1,119 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Startup banner shown when LMCache starts serving.
3
+
4
+ The banner is printed at most once per process, to ``stderr``, by the
5
+ ``lmcache`` CLI and by the vLLM connector integrations (scheduler role
6
+ only, so tensor-parallel deployments print a single banner). Setting the
7
+ ``LMCACHE_DISABLE_BANNER=1`` environment variable suppresses it.
8
+ """
9
+
10
+ # Standard
11
+ from typing import TextIO
12
+ import os
13
+
14
+ try:
15
+ # First Party
16
+ from lmcache import _version
17
+
18
+ _LMCACHE_VERSION = getattr(_version, "__version__", "unknown")
19
+ _LMCACHE_COMMIT = getattr(_version, "__commit_id__", "")
20
+ except ImportError: # pragma: no cover - version file is generated at build time
21
+ _LMCACHE_VERSION = "unknown"
22
+ _LMCACHE_COMMIT = ""
23
+
24
+ DISABLE_BANNER_ENV = "LMCACHE_DISABLE_BANNER"
25
+
26
+ LMCACHE_WEBSITE = "https://lmcache.ai/"
27
+ LMCACHE_RECIPES = "https://docs.lmcache.ai/recipes"
28
+ LMCACHE_LINKEDIN = "https://www.linkedin.com/company/lmcache-lab"
29
+
30
+ # Solarized palette, 24-bit ANSI escapes (TTY only): "LM" in bold italic
31
+ # orange (#cb4b16), "Cache" in cyan (#2aa198).
32
+ _LM_STYLE = "\x1b[1;3;38;2;203;75;22m"
33
+ _CACHE_STYLE = "\x1b[38;2;42;161;152m"
34
+ _DIM_STYLE = "\x1b[2m"
35
+ _RESET = "\x1b[0m"
36
+
37
+ # Figlet "standard" font, split into the two color groups.
38
+ _LM_ART = (
39
+ " _ __ __ ",
40
+ "| | | \\/ |",
41
+ "| | | |\\/| |",
42
+ "| |___| | | |",
43
+ "|_____|_| |_|",
44
+ )
45
+ _CACHE_ART = (
46
+ " ____ _ ",
47
+ " / ___|__ _ ___| |__ ___ ",
48
+ "| | / _` |/ __| '_ \\ / _ \\",
49
+ "| |__| (_| | (__| | | | __/",
50
+ " \\____\\__,_|\\___|_| |_|\\___|",
51
+ )
52
+ _RIGHT_TEXT_GAP = " "
53
+
54
+ _banner_printed = False
55
+
56
+
57
+ def _banner_disabled() -> bool:
58
+ """Return whether ``LMCACHE_DISABLE_BANNER`` is set to a truthy value."""
59
+ return os.getenv(DISABLE_BANNER_ENV, "").strip().lower() in ("1", "true", "yes")
60
+
61
+
62
+ def _render_banner(colored: bool) -> str:
63
+ """Render the banner text.
64
+
65
+ Args:
66
+ colored: Whether to wrap the logo in ANSI color escapes.
67
+
68
+ Returns:
69
+ The multi-line banner: the LMCache logo with the version (and
70
+ commit id when available), website, recipes, and LinkedIn links
71
+ on its right, and a final line describing the
72
+ ``LMCACHE_DISABLE_BANNER`` opt-out. A blank line surrounds the
73
+ banner on each side to set it apart from adjacent log output.
74
+ """
75
+ lm_style = _LM_STYLE if colored else ""
76
+ cache_style = _CACHE_STYLE if colored else ""
77
+ dim_style = _DIM_STYLE if colored else ""
78
+ reset = _RESET if colored else ""
79
+
80
+ version = f"LMCache v{_LMCACHE_VERSION}"
81
+ if _LMCACHE_COMMIT:
82
+ version += f" ({_LMCACHE_COMMIT[:9]})"
83
+ right_text = {
84
+ 1: version,
85
+ 2: f"Website: {LMCACHE_WEBSITE}",
86
+ 3: f"Recipes: {LMCACHE_RECIPES}",
87
+ 4: f"LinkedIn: {LMCACHE_LINKEDIN}",
88
+ }
89
+ lines = [""]
90
+ for row, (lm_part, cache_part) in enumerate(zip(_LM_ART, _CACHE_ART, strict=True)):
91
+ line = f"{lm_style}{lm_part}{reset} {cache_style}{cache_part}{reset}"
92
+ if row in right_text:
93
+ line += _RIGHT_TEXT_GAP + right_text[row]
94
+ lines.append(line)
95
+ lines.append(f"{dim_style}Set {DISABLE_BANNER_ENV}=1 to hide this banner.{reset}")
96
+ lines.append("")
97
+ return "\n".join(lines)
98
+
99
+
100
+ def print_banner_once(stream: TextIO) -> None:
101
+ """Print the LMCache startup banner to ``stream`` at most once.
102
+
103
+ The banner shows the LMCache logo, version, and website, followed by
104
+ a hint describing the ``LMCACHE_DISABLE_BANNER`` opt-out. ANSI colors
105
+ are used only when ``stream`` is a TTY. Subsequent calls in the same
106
+ process are no-ops, as are all calls when ``LMCACHE_DISABLE_BANNER``
107
+ is set to ``1``/``true``/``yes``.
108
+
109
+ Args:
110
+ stream: Destination text stream. Callers should pass
111
+ ``sys.stderr`` so the banner never interferes with
112
+ machine-readable stdout output.
113
+ """
114
+ global _banner_printed
115
+ if _banner_printed or _banner_disabled():
116
+ return
117
+ _banner_printed = True
118
+ stream.write(_render_banner(stream.isatty()) + "\n")
119
+ stream.flush()
@@ -1,34 +1,40 @@
1
1
  # SPDX-License-Identifier: Apache-2.0
2
2
  """CLI subcommand package.
3
3
 
4
- To add a new command:
5
-
6
- 1. Create a module with a :class:`BaseCommand` subclass.
7
- 2. Add one import + one entry to :data:`ALL_COMMANDS` below.
4
+ To add a new top-level command, simply create a new module (or sub-package
5
+ with an ``__init__.py``) under this package that defines a concrete
6
+ :class:`BaseCommand` subclass. It will be discovered and registered
7
+ automatically no edits to this file are required.
8
8
  """
9
9
 
10
10
  # First Party
11
11
  from lmcache.cli.commands.base import BaseCommand
12
- from lmcache.cli.commands.bench import BenchCommand
13
- from lmcache.cli.commands.describe import DescribeCommand
14
- from lmcache.cli.commands.kvcache import KVCacheCommand
15
- from lmcache.cli.commands.mock import MockCommand
16
- from lmcache.cli.commands.ping import PingCommand
17
- from lmcache.cli.commands.query import QueryCommand
18
- from lmcache.cli.commands.server import ServerCommand
19
- from lmcache.cli.commands.tool import ToolCommand
20
- from lmcache.cli.commands.trace import TraceCommand
21
-
22
- ALL_COMMANDS: list[BaseCommand] = [
23
- MockCommand(),
24
- KVCacheCommand(),
25
- DescribeCommand(),
26
- PingCommand(),
27
- QueryCommand(),
28
- ServerCommand(),
29
- BenchCommand(),
30
- ToolCommand(),
31
- TraceCommand(),
32
- ]
12
+ from lmcache.v1.utils.subclass_discovery import discover_subclasses
13
+
14
+
15
+ def _discover_commands() -> list[BaseCommand]:
16
+ """Scan direct submodules of this package and collect all concrete
17
+ :class:`BaseCommand` subclasses, returning one instance per class.
18
+
19
+ Import errors are intentionally re-raised: a broken CLI command
20
+ module should fail loudly rather than silently disappear from the
21
+ CLI.
22
+ """
23
+
24
+ def _raise(module_name: str, exc: Exception) -> None:
25
+ raise exc
26
+
27
+ return [
28
+ cls()
29
+ for cls in discover_subclasses(
30
+ __name__,
31
+ BaseCommand, # type: ignore[type-abstract]
32
+ module_filter=lambda name: name != "base",
33
+ on_import_error=_raise,
34
+ )
35
+ ]
36
+
37
+
38
+ ALL_COMMANDS: list[BaseCommand] = _discover_commands()
33
39
 
34
40
  __all__ = ["ALL_COMMANDS", "BaseCommand"]