lifeboatcache 0.1.0__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.
Files changed (98) hide show
  1. lifeboatcache-0.1.0/.gitignore +15 -0
  2. lifeboatcache-0.1.0/PKG-INFO +121 -0
  3. lifeboatcache-0.1.0/README.md +92 -0
  4. lifeboatcache-0.1.0/presets/base.yaml +16 -0
  5. lifeboatcache-0.1.0/presets/dev_cpu.yaml +22 -0
  6. lifeboatcache-0.1.0/presets/fleet_50k.yaml +53 -0
  7. lifeboatcache-0.1.0/presets/max_accuracy.yaml +15 -0
  8. lifeboatcache-0.1.0/presets/max_concurrency.yaml +15 -0
  9. lifeboatcache-0.1.0/presets/single_node_gpu.yaml +18 -0
  10. lifeboatcache-0.1.0/presets/storage_efficient.yaml +13 -0
  11. lifeboatcache-0.1.0/pyproject.toml +78 -0
  12. lifeboatcache-0.1.0/src/lifeboat_cache/__init__.py +7 -0
  13. lifeboatcache-0.1.0/src/lifeboat_cache/compress/__init__.py +57 -0
  14. lifeboatcache-0.1.0/src/lifeboat_cache/compress/accuracy.py +53 -0
  15. lifeboatcache-0.1.0/src/lifeboat_cache/compress/base.py +229 -0
  16. lifeboatcache-0.1.0/src/lifeboat_cache/compress/calibration.py +81 -0
  17. lifeboatcache-0.1.0/src/lifeboat_cache/compress/demote.py +16 -0
  18. lifeboatcache-0.1.0/src/lifeboat_cache/compress/fp8.py +160 -0
  19. lifeboatcache-0.1.0/src/lifeboat_cache/compress/kvtc.py +140 -0
  20. lifeboatcache-0.1.0/src/lifeboat_cache/compress/live.py +284 -0
  21. lifeboatcache-0.1.0/src/lifeboat_cache/compress/oscar2.py +166 -0
  22. lifeboatcache-0.1.0/src/lifeboat_cache/compress/turboquant.py +131 -0
  23. lifeboatcache-0.1.0/src/lifeboat_cache/config/__init__.py +36 -0
  24. lifeboatcache-0.1.0/src/lifeboat_cache/config/cli.py +276 -0
  25. lifeboatcache-0.1.0/src/lifeboat_cache/config/loader.py +278 -0
  26. lifeboatcache-0.1.0/src/lifeboat_cache/config/paths.py +22 -0
  27. lifeboatcache-0.1.0/src/lifeboat_cache/config/schema.py +450 -0
  28. lifeboatcache-0.1.0/src/lifeboat_cache/control/__init__.py +54 -0
  29. lifeboatcache-0.1.0/src/lifeboat_cache/control/config_push.py +243 -0
  30. lifeboatcache-0.1.0/src/lifeboat_cache/control/controld.py +187 -0
  31. lifeboatcache-0.1.0/src/lifeboat_cache/control/membership.py +216 -0
  32. lifeboatcache-0.1.0/src/lifeboat_cache/control/placement.py +81 -0
  33. lifeboatcache-0.1.0/src/lifeboat_cache/control/router_export.py +87 -0
  34. lifeboatcache-0.1.0/src/lifeboat_cache/control/telemetry_agg.py +101 -0
  35. lifeboatcache-0.1.0/src/lifeboat_cache/core/__init__.py +59 -0
  36. lifeboatcache-0.1.0/src/lifeboat_cache/core/coalesce.py +100 -0
  37. lifeboatcache-0.1.0/src/lifeboat_cache/core/hashing.py +96 -0
  38. lifeboatcache-0.1.0/src/lifeboat_cache/core/header.py +158 -0
  39. lifeboatcache-0.1.0/src/lifeboat_cache/core/keys.py +57 -0
  40. lifeboatcache-0.1.0/src/lifeboat_cache/core/ring.py +52 -0
  41. lifeboatcache-0.1.0/src/lifeboat_cache/dashboard/__init__.py +334 -0
  42. lifeboatcache-0.1.0/src/lifeboat_cache/dashboard/static/index.html +582 -0
  43. lifeboatcache-0.1.0/src/lifeboat_cache/device/__init__.py +48 -0
  44. lifeboatcache-0.1.0/src/lifeboat_cache/device/base.py +75 -0
  45. lifeboatcache-0.1.0/src/lifeboat_cache/device/cpu.py +15 -0
  46. lifeboatcache-0.1.0/src/lifeboat_cache/device/cuda.py +51 -0
  47. lifeboatcache-0.1.0/src/lifeboat_cache/errors.py +31 -0
  48. lifeboatcache-0.1.0/src/lifeboat_cache/index/__init__.py +67 -0
  49. lifeboatcache-0.1.0/src/lifeboat_cache/index/backends.py +207 -0
  50. lifeboatcache-0.1.0/src/lifeboat_cache/index/entry.py +35 -0
  51. lifeboatcache-0.1.0/src/lifeboat_cache/index/hashring.py +104 -0
  52. lifeboatcache-0.1.0/src/lifeboat_cache/index/local.py +136 -0
  53. lifeboatcache-0.1.0/src/lifeboat_cache/index/sharded.py +101 -0
  54. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/__init__.py +1 -0
  55. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/host.py +104 -0
  56. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/k8s/__init__.py +76 -0
  57. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/lifeboat_store.py +386 -0
  58. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/lmcache_adapter.py +395 -0
  59. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/lmcache_defaults.py +54 -0
  60. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/policies.py +39 -0
  61. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/registration.py +60 -0
  62. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/serde.py +109 -0
  63. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/sglang_backend.py +187 -0
  64. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/sglang_plugin.py +110 -0
  65. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/vllm_connector.py +50 -0
  66. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/vllm_cpu_patches.py +116 -0
  67. lifeboatcache-0.1.0/src/lifeboat_cache/integrations/vllm_plugin.py +80 -0
  68. lifeboatcache-0.1.0/src/lifeboat_cache/policy/__init__.py +98 -0
  69. lifeboatcache-0.1.0/src/lifeboat_cache/policy/accuracy_guard.py +105 -0
  70. lifeboatcache-0.1.0/src/lifeboat_cache/policy/admission.py +60 -0
  71. lifeboatcache-0.1.0/src/lifeboat_cache/policy/base.py +68 -0
  72. lifeboatcache-0.1.0/src/lifeboat_cache/policy/classic.py +205 -0
  73. lifeboatcache-0.1.0/src/lifeboat_cache/policy/episodic.py +289 -0
  74. lifeboatcache-0.1.0/src/lifeboat_cache/policy/predictive.py +89 -0
  75. lifeboatcache-0.1.0/src/lifeboat_cache/policy/reuse_score.py +100 -0
  76. lifeboatcache-0.1.0/src/lifeboat_cache/registry.py +114 -0
  77. lifeboatcache-0.1.0/src/lifeboat_cache/session/__init__.py +142 -0
  78. lifeboatcache-0.1.0/src/lifeboat_cache/sim/__init__.py +110 -0
  79. lifeboatcache-0.1.0/src/lifeboat_cache/sim/fleet.py +148 -0
  80. lifeboatcache-0.1.0/src/lifeboat_cache/sim/trace.py +78 -0
  81. lifeboatcache-0.1.0/src/lifeboat_cache/storage/__init__.py +198 -0
  82. lifeboatcache-0.1.0/src/lifeboat_cache/storage/backpressure.py +89 -0
  83. lifeboatcache-0.1.0/src/lifeboat_cache/storage/circuit_breaker.py +89 -0
  84. lifeboatcache-0.1.0/src/lifeboat_cache/storage/coalesced.py +63 -0
  85. lifeboatcache-0.1.0/src/lifeboat_cache/storage/doca_memos.py +82 -0
  86. lifeboatcache-0.1.0/src/lifeboat_cache/storage/filesystem.py +177 -0
  87. lifeboatcache-0.1.0/src/lifeboat_cache/storage/manager.py +238 -0
  88. lifeboatcache-0.1.0/src/lifeboat_cache/storage/memory.py +42 -0
  89. lifeboatcache-0.1.0/src/lifeboat_cache/storage/ontap.py +385 -0
  90. lifeboatcache-0.1.0/src/lifeboat_cache/storage/rdma_nixl.py +100 -0
  91. lifeboatcache-0.1.0/src/lifeboat_cache/storage/s3.py +181 -0
  92. lifeboatcache-0.1.0/src/lifeboat_cache/storage/tier.py +75 -0
  93. lifeboatcache-0.1.0/src/lifeboat_cache/telemetry/__init__.py +89 -0
  94. lifeboatcache-0.1.0/src/lifeboat_cache/telemetry/metrics.py +86 -0
  95. lifeboatcache-0.1.0/src/lifeboat_cache/tenancy/__init__.py +98 -0
  96. lifeboatcache-0.1.0/src/lifeboat_cache/tenancy/qos.py +76 -0
  97. lifeboatcache-0.1.0/src/lifeboat_cache/tenancy/quota.py +73 -0
  98. lifeboatcache-0.1.0/upstream_patches/README.md +124 -0
@@ -0,0 +1,15 @@
1
+ .venv/
2
+ vendor/
3
+ __pycache__/
4
+ *.pyc
5
+ *.so
6
+ *.egg-info/
7
+ build/
8
+ dist/
9
+ .pytest_cache/
10
+ .coverage
11
+ htmlcov/
12
+ scratch_*.log
13
+ *.tmp
14
+ target/
15
+ .lifeboat_kv/
@@ -0,0 +1,121 @@
1
+ Metadata-Version: 2.5
2
+ Name: lifeboatcache
3
+ Version: 0.1.0
4
+ Summary: Lifeboat Cache — tiered, compressed, persistent KV cache for vLLM, SGLang and Lifeboat, with a built-in dashboard
5
+ Author-email: "Iterate.ai" <brian@iterate.ai>
6
+ License: Proprietary
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: numpy>=1.24
9
+ Requires-Dist: pydantic<3,>=2.7
10
+ Requires-Dist: pyyaml<7,>=6
11
+ Provides-Extra: dev
12
+ Requires-Dist: cython; extra == 'dev'
13
+ Requires-Dist: maturin<2,>=1.7; extra == 'dev'
14
+ Requires-Dist: moto<6,>=5; extra == 'dev'
15
+ Requires-Dist: openai; extra == 'dev'
16
+ Requires-Dist: pytest-cov>=5; extra == 'dev'
17
+ Requires-Dist: pytest<9,>=8; extra == 'dev'
18
+ Provides-Extra: engines
19
+ Requires-Dist: lmcache<0.6,>=0.5.6; extra == 'engines'
20
+ Requires-Dist: nixl<2,>=1.5.0; extra == 'engines'
21
+ Requires-Dist: sglang<0.6,>=0.5.19; extra == 'engines'
22
+ Requires-Dist: vllm<0.33,>=0.32.0; extra == 'engines'
23
+ Provides-Extra: s3
24
+ Requires-Dist: boto3>=1.28; extra == 's3'
25
+ Provides-Extra: sglang
26
+ Provides-Extra: vllm
27
+ Requires-Dist: lmcache<0.6,>=0.5.6; extra == 'vllm'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # Lifeboat Cache
31
+
32
+ Tiered, compressed, persistent KV cache for **vLLM**, **SGLang**, and **Lifeboat** (which
33
+ embeds SGLang), with a built-in dashboard to configure, monitor and observe it.
34
+
35
+ ```bash
36
+ pip install "lifeboatcache[vllm]" # into the environment that runs vLLM
37
+ pip install lifeboatcache # into the environment that runs SGLang / Lifeboat
38
+ ```
39
+
40
+ Installing registers engine plugins; nothing else is needed to start. With no config file,
41
+ Lifeboat writes KV to local disk under `~/.lifeboat_cache/kv`, compresses it with fp8, and
42
+ serves the dashboard on <http://127.0.0.1:9400>.
43
+
44
+ ## Turn it on
45
+
46
+ | Engine | How |
47
+ |---|---|
48
+ | vLLM | `LIFEBOAT_CACHE=1 vllm serve <model>` — or explicitly `--kv-transfer-config '{"kv_connector":"LifeboatConnector","kv_role":"kv_both"}'` |
49
+ | SGLang | `LIFEBOAT_CACHE=1 python -m sglang.launch_server --model-path <model>` |
50
+ | Lifeboat | set `LIFEBOAT_CACHE=1` in the Lifeboat container's environment, with `lifeboatcache` installed in its Python env |
51
+
52
+ What happens underneath:
53
+
54
+ - **vLLM** — `LifeboatConnector` is LMCache's multiprocess connector with Lifeboat defaults: it
55
+ auto-starts a local LMCache server (port 6555) whose L2 storage is the Lifeboat adapter.
56
+ GPU ↔ host movement is LMCache's; everything below host RAM is Lifeboat.
57
+ - **SGLang / Lifeboat** — Lifeboat is a HiCache storage backend (`--hicache-storage-backend
58
+ dynamic`). With `LIFEBOAT_CACHE=1` the plugin enables HiCache and selects the backend unless
59
+ the launch already chose a storage backend. Explicit flags work too:
60
+
61
+ ```bash
62
+ python -m sglang.launch_server --model-path <model> --enable-hierarchical-cache \
63
+ --hicache-storage-backend dynamic \
64
+ --hicache-storage-backend-extra-config '{"backend_name":"lifeboat","module_path":"lifeboat_cache.integrations.sglang_backend","class_name":"LifeboatHiCacheStorage"}'
65
+ ```
66
+
67
+ ## Storage targets and the local fallback
68
+
69
+ Targets are tried in order; the first usable one takes new writes. Each is write-probed at
70
+ startup. One that can't be reached (ONTAP/NFS export not mounted, S3 without credentials) is
71
+ skipped with the reason shown on the dashboard, and if nothing persistent is left, KV goes to
72
+ `storage.fallback_local` on local disk.
73
+
74
+ ```yaml
75
+ storage:
76
+ tiers:
77
+ - {name: ontap, type: ontap, enabled: true, mount: /mnt/kvcache, protocol: pnfs_rdma}
78
+ - {name: nfs, type: nfs, enabled: true, mount: /mnt/nfs, path: /mnt/nfs/lifeboat/kv}
79
+ - {name: s3, type: s3, enabled: true, bucket: kv-archive, region: us-east-1}
80
+ fallback_local: {enabled: true, path: ~/.lifeboat_cache/kv, capacity_gb: 50}
81
+ ```
82
+
83
+ Persisted KV survives restarts: on startup the index is rebuilt from disk in the background.
84
+
85
+ ## Dashboard
86
+
87
+ `http://127.0.0.1:9400` on the node (use `ssh -L 9400:localhost:9400 <node>` from your
88
+ laptop). It shows the cache hit rate, KV served, bytes saved by compression and the codec's
89
+ sampled reconstruction error, per-target status (circuit breaker, usage, queue), evictions,
90
+ and startup recovery. The **Configure** tab edits storage targets, the local fallback, the
91
+ compression codec per rung, the eviction policy and the write mode; changes are validated,
92
+ applied live, and saved to the config file (startup-bound sections are flagged "restart
93
+ required"). `/metrics` serves Prometheus text (also on port 9402).
94
+
95
+ To expose it beyond localhost, set `dashboard.host: 0.0.0.0` **and** `dashboard.auth_token`;
96
+ open the page once with `?token=<token>`.
97
+
98
+ CLI: `lifeboat-cache status` prints the same numbers; `lifeboat-cache init` writes a starter
99
+ config; `lifeboat-cache server` runs a standalone Lifeboat-backed LMCache server for several
100
+ vLLM instances to share.
101
+
102
+ ## Configuration
103
+
104
+ One YAML file, resolved as: `--config` / `$LIFEBOAT_CACHE_CONFIG` →
105
+ `~/.lifeboat_cache/lifeboat.yaml` → built-in defaults (`$LIFEBOAT_CACHE_HOME` moves the home
106
+ directory). `lifeboat-cache config show` prints the resolved config. Presets ship with the
107
+ package: `extends: single_node_gpu`.
108
+
109
+ ## Compression — what the numbers say
110
+
111
+ Measured on real Qwen3 KV (2,048-token prefix, see `docs/`):
112
+
113
+ | codec | bits/value | Qwen3-4B perplexity (base 2.297) |
114
+ |---|---|---|
115
+ | fp8 (default) | 8.0 | 2.293 |
116
+ | turboquant4, keep first/last 2 layers | 6.2 | 2.300 |
117
+ | turboquant3 | 4.0 | 824 (breaks the model) |
118
+ | oscar2 on 2,048-token chunks | 5.0 | 72 (breaks the model) |
119
+
120
+ fp8 is the default for every stored rung. The dashboard shows the sampled reconstruction error
121
+ of whatever codec is live.
@@ -0,0 +1,92 @@
1
+ # Lifeboat Cache
2
+
3
+ Tiered, compressed, persistent KV cache for **vLLM**, **SGLang**, and **Lifeboat** (which
4
+ embeds SGLang), with a built-in dashboard to configure, monitor and observe it.
5
+
6
+ ```bash
7
+ pip install "lifeboatcache[vllm]" # into the environment that runs vLLM
8
+ pip install lifeboatcache # into the environment that runs SGLang / Lifeboat
9
+ ```
10
+
11
+ Installing registers engine plugins; nothing else is needed to start. With no config file,
12
+ Lifeboat writes KV to local disk under `~/.lifeboat_cache/kv`, compresses it with fp8, and
13
+ serves the dashboard on <http://127.0.0.1:9400>.
14
+
15
+ ## Turn it on
16
+
17
+ | Engine | How |
18
+ |---|---|
19
+ | vLLM | `LIFEBOAT_CACHE=1 vllm serve <model>` — or explicitly `--kv-transfer-config '{"kv_connector":"LifeboatConnector","kv_role":"kv_both"}'` |
20
+ | SGLang | `LIFEBOAT_CACHE=1 python -m sglang.launch_server --model-path <model>` |
21
+ | Lifeboat | set `LIFEBOAT_CACHE=1` in the Lifeboat container's environment, with `lifeboatcache` installed in its Python env |
22
+
23
+ What happens underneath:
24
+
25
+ - **vLLM** — `LifeboatConnector` is LMCache's multiprocess connector with Lifeboat defaults: it
26
+ auto-starts a local LMCache server (port 6555) whose L2 storage is the Lifeboat adapter.
27
+ GPU ↔ host movement is LMCache's; everything below host RAM is Lifeboat.
28
+ - **SGLang / Lifeboat** — Lifeboat is a HiCache storage backend (`--hicache-storage-backend
29
+ dynamic`). With `LIFEBOAT_CACHE=1` the plugin enables HiCache and selects the backend unless
30
+ the launch already chose a storage backend. Explicit flags work too:
31
+
32
+ ```bash
33
+ python -m sglang.launch_server --model-path <model> --enable-hierarchical-cache \
34
+ --hicache-storage-backend dynamic \
35
+ --hicache-storage-backend-extra-config '{"backend_name":"lifeboat","module_path":"lifeboat_cache.integrations.sglang_backend","class_name":"LifeboatHiCacheStorage"}'
36
+ ```
37
+
38
+ ## Storage targets and the local fallback
39
+
40
+ Targets are tried in order; the first usable one takes new writes. Each is write-probed at
41
+ startup. One that can't be reached (ONTAP/NFS export not mounted, S3 without credentials) is
42
+ skipped with the reason shown on the dashboard, and if nothing persistent is left, KV goes to
43
+ `storage.fallback_local` on local disk.
44
+
45
+ ```yaml
46
+ storage:
47
+ tiers:
48
+ - {name: ontap, type: ontap, enabled: true, mount: /mnt/kvcache, protocol: pnfs_rdma}
49
+ - {name: nfs, type: nfs, enabled: true, mount: /mnt/nfs, path: /mnt/nfs/lifeboat/kv}
50
+ - {name: s3, type: s3, enabled: true, bucket: kv-archive, region: us-east-1}
51
+ fallback_local: {enabled: true, path: ~/.lifeboat_cache/kv, capacity_gb: 50}
52
+ ```
53
+
54
+ Persisted KV survives restarts: on startup the index is rebuilt from disk in the background.
55
+
56
+ ## Dashboard
57
+
58
+ `http://127.0.0.1:9400` on the node (use `ssh -L 9400:localhost:9400 <node>` from your
59
+ laptop). It shows the cache hit rate, KV served, bytes saved by compression and the codec's
60
+ sampled reconstruction error, per-target status (circuit breaker, usage, queue), evictions,
61
+ and startup recovery. The **Configure** tab edits storage targets, the local fallback, the
62
+ compression codec per rung, the eviction policy and the write mode; changes are validated,
63
+ applied live, and saved to the config file (startup-bound sections are flagged "restart
64
+ required"). `/metrics` serves Prometheus text (also on port 9402).
65
+
66
+ To expose it beyond localhost, set `dashboard.host: 0.0.0.0` **and** `dashboard.auth_token`;
67
+ open the page once with `?token=<token>`.
68
+
69
+ CLI: `lifeboat-cache status` prints the same numbers; `lifeboat-cache init` writes a starter
70
+ config; `lifeboat-cache server` runs a standalone Lifeboat-backed LMCache server for several
71
+ vLLM instances to share.
72
+
73
+ ## Configuration
74
+
75
+ One YAML file, resolved as: `--config` / `$LIFEBOAT_CACHE_CONFIG` →
76
+ `~/.lifeboat_cache/lifeboat.yaml` → built-in defaults (`$LIFEBOAT_CACHE_HOME` moves the home
77
+ directory). `lifeboat-cache config show` prints the resolved config. Presets ship with the
78
+ package: `extends: single_node_gpu`.
79
+
80
+ ## Compression — what the numbers say
81
+
82
+ Measured on real Qwen3 KV (2,048-token prefix, see `docs/`):
83
+
84
+ | codec | bits/value | Qwen3-4B perplexity (base 2.297) |
85
+ |---|---|---|
86
+ | fp8 (default) | 8.0 | 2.293 |
87
+ | turboquant4, keep first/last 2 layers | 6.2 | 2.300 |
88
+ | turboquant3 | 4.0 | 824 (breaks the model) |
89
+ | oscar2 on 2,048-token chunks | 5.0 | 72 (breaks the model) |
90
+
91
+ fp8 is the default for every stored rung. The dashboard shows the sampled reconstruction error
92
+ of whatever codec is live.
@@ -0,0 +1,16 @@
1
+ # Base preset: codec definitions + fleet-neutral defaults. Other presets extend this.
2
+ # (Defining codecs here means any preset keeping the default ladder validates.)
3
+ compression:
4
+ recompress_on_demote: true
5
+ codecs:
6
+ turboquant4: {type: turboquant, bits: 4, keep_bf16_layers: [0, 1, -2, -1], group_size: 64}
7
+ turboquant3: {type: turboquant, bits: 3}
8
+ oscar2: {type: oscar, bits: 2, rotation: calibrated, sink_tokens: 64, recent_tokens: 256}
9
+ kvtc: {type: kvtc, pca_rank: auto, entropy_coder: ans}
10
+ fp8: {type: fp8}
11
+ accuracy_guard:
12
+ enabled: true
13
+ sample_rate: 0.01
14
+ metric: logit_kl
15
+ threshold: 0.05
16
+ action: raise_precision
@@ -0,0 +1,22 @@
1
+ # dev_cpu: single-process CPU dev on a Mac ("fleet of size one"). No control plane.
2
+ extends: base.yaml
3
+ device: cpu
4
+ compression:
5
+ ladder: {gpu: turboquant3, cpu: turboquant3, local_nvme: kvtc, shared: kvtc, archive: kvtc}
6
+ control_plane:
7
+ enabled: false
8
+ membership: static
9
+ metadata_store: memory
10
+ offline_mode: local_only
11
+ eviction:
12
+ l1_policy: lru
13
+ episodic: {enabled: false}
14
+ storage:
15
+ enabled: true
16
+ write_mode: low_latency
17
+ tiers:
18
+ - {name: local, type: filesystem, enabled: true, path: ./.lifeboat_kv, scope: node, capacity_gb: 2}
19
+ tenancy:
20
+ enabled: false
21
+ telemetry:
22
+ prometheus: {enabled: false}
@@ -0,0 +1,53 @@
1
+ # fleet_50k: 50,000+ GPU fleet. Control plane on, gossip membership, etcd metadata,
2
+ # heavy sharding + replication, topology-aware placement, full telemetry.
3
+ extends: base.yaml
4
+ device: auto
5
+ topology:
6
+ discovery: k8s
7
+ numa_aware: true
8
+ control_plane:
9
+ enabled: true
10
+ membership: gossip
11
+ metadata_store: etcd
12
+ index_shards: 4096
13
+ replication_factor: 3
14
+ heartbeat_ms: 1000
15
+ offline_mode: cached_placement
16
+ config_push: {enabled: true, canary_percent: 5, auto_rollback_on_regression: true}
17
+ compression:
18
+ ladder: {gpu: turboquant4, cpu: turboquant3, local_nvme: kvtc, shared: kvtc, archive: kvtc}
19
+ eviction:
20
+ l1_policy: episodic
21
+ episodic: {enabled: true, persist_evicted_episodes: true, prefetch_on_topic_return: true}
22
+ reuse:
23
+ cross_node_p2p: {enabled: true, transport: nixl, max_hops: 1, prefer_nvlink_domain: true}
24
+ storage:
25
+ enabled: true
26
+ write_mode: auto
27
+ placement:
28
+ write_local_first: true
29
+ replicate_to_shared_async: true
30
+ read_nearest: true
31
+ hot_object_replicas: 3
32
+ hotspot_threshold_rps: 500
33
+ tiers:
34
+ - {name: nvme, type: nvme, enabled: true, path: /mnt/nvme/kv, io: io_uring,
35
+ direct_io: true, capacity_gb: 800, scope: node}
36
+ - {name: ontap, type: ontap, enabled: true, mount: /mnt/kvcache, protocol: pnfs_rdma,
37
+ prefer_nearest_flexcache: true, fabricpool_cold_after_h: 24, scope: cluster}
38
+ - {name: s3, type: s3, enabled: true, bucket: kv-archive, multipart_parallelism: 8,
39
+ byte_range_reads: true, scope: region}
40
+ - {name: rdma, type: nixl, enabled: true, scope: pod}
41
+ backpressure:
42
+ queue_depth_per_tier: 16384
43
+ shed_below_reuse_score: 0.1
44
+ circuit_breaker: {error_rate: 0.2, open_s: 30}
45
+ tenancy:
46
+ enabled: true
47
+ default_qos: throughput
48
+ fair_share: true
49
+ telemetry:
50
+ prometheus: {enabled: true, port: 9402, max_label_cardinality: 10000}
51
+ otel: {enabled: true, endpoint: "otel-collector:4317", trace_sample_rate: 0.001}
52
+ chargeback_per_tenant: true
53
+ export_locality_to_router: {enabled: true, target: dynamo}
@@ -0,0 +1,15 @@
1
+ # max_accuracy: preserve quality. Higher-precision codecs, strict accuracy guard.
2
+ extends: base.yaml
3
+ device: auto
4
+ compression:
5
+ ladder: {gpu: fp8, cpu: turboquant4, local_nvme: turboquant4, shared: turboquant4, archive: kvtc}
6
+ recompress_on_demote: true
7
+ accuracy_guard:
8
+ enabled: true
9
+ sample_rate: 0.05
10
+ metric: logit_kl
11
+ threshold: 0.01
12
+ action: raise_precision
13
+ eviction:
14
+ l1_policy: episodic
15
+ episodic: {enabled: true, per_layer_budget: sensitivity}
@@ -0,0 +1,15 @@
1
+ # max_concurrency: throughput-first. Aggressive coalescing, write-behind, low-latency codecs.
2
+ extends: base.yaml
3
+ device: auto
4
+ compression:
5
+ ladder: {gpu: turboquant4, cpu: turboquant4, local_nvme: turboquant4, shared: kvtc, archive: kvtc}
6
+ eviction:
7
+ l1_policy: arc
8
+ admission: {enabled: true, min_reuse_score: 0.1, write_behind: always}
9
+ storage:
10
+ write_mode: low_latency
11
+ coalesce: {target_tokens: 4096, min_tokens: 512, max_tokens: 8192, adaptive: true, flush_interval_ms: 20}
12
+ backpressure: {queue_depth_per_tier: 16384, shed_below_reuse_score: 0.2}
13
+ tenancy:
14
+ default_qos: throughput
15
+ fair_share: true
@@ -0,0 +1,18 @@
1
+ # single_node_gpu: one GPU node, local NVMe tier, no control plane.
2
+ extends: base.yaml
3
+ device: cuda
4
+ control_plane:
5
+ enabled: false
6
+ membership: static
7
+ metadata_store: memory
8
+ offline_mode: local_only
9
+ eviction:
10
+ l1_policy: episodic
11
+ storage:
12
+ enabled: true
13
+ write_mode: auto
14
+ tiers:
15
+ - {name: nvme, type: nvme, enabled: true, path: /mnt/nvme/kv, io: io_uring,
16
+ direct_io: true, capacity_gb: 800, scope: node}
17
+ telemetry:
18
+ prometheus: {enabled: true, port: 9402}
@@ -0,0 +1,13 @@
1
+ # storage_efficient: minimize bytes. Aggressive low-bit codecs, recompress on demote, dedup.
2
+ extends: base.yaml
3
+ device: auto
4
+ compression:
5
+ ladder: {gpu: turboquant4, cpu: turboquant3, local_nvme: oscar2, shared: kvtc, archive: kvtc}
6
+ recompress_on_demote: true
7
+ eviction:
8
+ l1_policy: episodic
9
+ admission: {enabled: true, min_reuse_score: 0.35, write_behind: idle}
10
+ storage:
11
+ write_mode: efficient
12
+ coalesce: {target_tokens: 8192, min_tokens: 1024, max_tokens: 8192, adaptive: true, flush_interval_ms: 100}
13
+ index: {content_addressed: true, dedup: true, dedup_scope: global, tenant_salted_hashing: true}
@@ -0,0 +1,78 @@
1
+ [project]
2
+ # Distribution name is `lifeboatcache` (pip install lifeboatcache); the import package is
3
+ # `lifeboat_cache`.
4
+ name = "lifeboatcache"
5
+ version = "0.1.0"
6
+ description = "Lifeboat Cache — tiered, compressed, persistent KV cache for vLLM, SGLang and Lifeboat, with a built-in dashboard"
7
+ readme = "README.md"
8
+ # 3.10+: SGLang (and the Lifeboat product that embeds it) supports 3.10.
9
+ requires-python = ">=3.10"
10
+ license = { text = "Proprietary" }
11
+ authors = [{ name = "Iterate.ai", email = "brian@iterate.ai" }]
12
+
13
+ # Supported upstream ranges. Vendored at: vllm v0.32.0, lmcache v0.5.6,
14
+ # sglang v0.5.22, nixl v1.5.0 (see docs/VERSIONS.md). These are installed
15
+ # editable from vendor/ during dev; ranges here gate the version-compat test.
16
+ dependencies = [
17
+ "pydantic>=2.7,<3",
18
+ "pyyaml>=6,<7",
19
+ "numpy>=1.24",
20
+ ]
21
+
22
+ [project.optional-dependencies]
23
+ # vLLM path: Lifeboat sits under LMCache's MP server. Install into the env that runs vLLM.
24
+ vllm = ["lmcache>=0.5.6,<0.6"]
25
+ # SGLang / Lifeboat path: nothing extra beyond SGLang itself (already in that env).
26
+ sglang = []
27
+ s3 = ["boto3>=1.28"]
28
+ # Upstream engines — pinned supported ranges (installed editable from vendor/ in dev).
29
+ # vllm 0.32.0: builds on Apple clang (0.31.0 does NOT — OpenMP/structured-binding
30
+ # error), but 0.32.0 has a stale CPU slot-mapping fallback. We repair it at runtime
31
+ # via lifeboat_cache.integrations.vllm_cpu_patches. See upstream_patches/README.md §2.
32
+ engines = [
33
+ "vllm>=0.32.0,<0.33",
34
+ "lmcache>=0.5.6,<0.6",
35
+ "sglang>=0.5.19,<0.6",
36
+ "nixl>=1.5.0,<2",
37
+ ]
38
+ dev = [
39
+ "maturin>=1.7,<2",
40
+ "pytest>=8,<9",
41
+ "pytest-cov>=5",
42
+ "moto>=5,<6",
43
+ "Cython",
44
+ "openai",
45
+ ]
46
+
47
+ [project.scripts]
48
+ lifeboat-cache = "lifeboat_cache.config.cli:main"
49
+ lifeboat-controld = "lifeboat_cache.control.controld:main"
50
+
51
+ # Loaded automatically by the engines in every process once the package is installed.
52
+ [project.entry-points."vllm.general_plugins"]
53
+ lifeboat = "lifeboat_cache.integrations.vllm_plugin:register"
54
+
55
+ [project.entry-points."sglang.srt.plugins"]
56
+ lifeboat = "lifeboat_cache.integrations.sglang_plugin:register"
57
+
58
+ [build-system]
59
+ requires = ["hatchling"]
60
+ build-backend = "hatchling.build"
61
+
62
+ [tool.hatch.build.targets.wheel]
63
+ packages = ["src/lifeboat_cache"]
64
+
65
+ [tool.hatch.build.targets.wheel.force-include]
66
+ "presets" = "lifeboat_cache/presets"
67
+
68
+ [tool.hatch.build.targets.sdist]
69
+ include = ["src/lifeboat_cache", "presets", "README.md", "pyproject.toml"]
70
+
71
+ [tool.pytest.ini_options]
72
+ testpaths = ["tests"]
73
+ pythonpath = ["src"]
74
+ markers = [
75
+ "requires_gpu: needs a CUDA/ROCm GPU (skipped on Mac)",
76
+ "requires_docker: needs docker/docker-compose",
77
+ "requires_cluster: needs a multi-node cluster",
78
+ ]
@@ -0,0 +1,7 @@
1
+ """Lifeboat Cache — commercial LMCache plugin (L2 storage, serde, policies).
2
+
3
+ See the project brief / docs/ for architecture. This package is import-safe on a
4
+ CPU-only Mac (the "fleet of size one") and on GPU fleets alike.
5
+ """
6
+
7
+ __version__ = "0.0.0"
@@ -0,0 +1,57 @@
1
+ """CPU reference compression layer for Lifeboat Cache.
2
+
3
+ A set of KV-cache codecs behind one :class:`Codec` interface, driven by the
4
+ ``compression`` config section. Every codec is pure-numpy (torch optional) and produces a
5
+ **self-describing blob** so ``decode`` needs no external arguments.
6
+
7
+ Codecs (each approximates a published method; see the module docstrings for exactly what is
8
+ reproduced vs. approximated):
9
+
10
+ * ``turboquant`` — group-wise affine int3/int4 with float16-kept layers.
11
+ * ``fp8`` — e4m3 / e5m2 emulation via an exact FP8 value grid.
12
+ * ``oscar`` — 2-bit middle + full-precision sink/recent tokens + optional rotation.
13
+ * ``kvtc`` — PCA + quantized coefficients/residual + zlib (ANS stand-in).
14
+
15
+ Importing this package registers all four codec factories, so
16
+ :func:`build_codecs` can instantiate any ladder from config.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ from .accuracy import cosine, logit_kl, mse, tensor_relative_error
21
+ from .base import (
22
+ Codec,
23
+ build_codecs,
24
+ create_codec,
25
+ pack_arrays,
26
+ pack_blob,
27
+ register_codec,
28
+ unpack_arrays,
29
+ unpack_blob,
30
+ )
31
+ from .calibration import CalibrationProfile
32
+ from .demote import recompress
33
+ from .fp8 import FP8Codec
34
+ from .kvtc import KVTCCodec
35
+ from .oscar2 import Oscar2Codec
36
+ from .turboquant import TurboQuantCodec
37
+
38
+ __all__ = [
39
+ "Codec",
40
+ "register_codec",
41
+ "create_codec",
42
+ "build_codecs",
43
+ "pack_blob",
44
+ "unpack_blob",
45
+ "pack_arrays",
46
+ "unpack_arrays",
47
+ "TurboQuantCodec",
48
+ "FP8Codec",
49
+ "Oscar2Codec",
50
+ "KVTCCodec",
51
+ "CalibrationProfile",
52
+ "recompress",
53
+ "logit_kl",
54
+ "cosine",
55
+ "mse",
56
+ "tensor_relative_error",
57
+ ]
@@ -0,0 +1,53 @@
1
+ """Accuracy metrics for the compression accuracy-guard.
2
+
3
+ The guard samples a fraction of writes, decodes them, and compares against the original to
4
+ decide whether a codec is degrading quality (config ``compression.accuracy_guard.metric``).
5
+ The headline metric is softmax KL on logits — the distributional distance that actually
6
+ matters for generation quality — plus cheaper tensor-space helpers.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import numpy as np
11
+
12
+ _EPS = 1e-12
13
+
14
+
15
+ def _log_softmax(z: np.ndarray) -> np.ndarray:
16
+ z = z - z.max(axis=-1, keepdims=True)
17
+ return z - np.log(np.exp(z).sum(axis=-1, keepdims=True) + _EPS)
18
+
19
+
20
+ def logit_kl(p_logits: np.ndarray, q_logits: np.ndarray) -> float:
21
+ """Mean KL(softmax(p) || softmax(q)) over the last axis.
22
+
23
+ Zero iff the two logit tensors induce the same distribution (identical logits, or logits
24
+ differing only by a per-row additive constant), strictly positive otherwise. Computed in
25
+ log-space for numerical stability.
26
+ """
27
+ lp = _log_softmax(np.asarray(p_logits, dtype=np.float64))
28
+ lq = _log_softmax(np.asarray(q_logits, dtype=np.float64))
29
+ p = np.exp(lp)
30
+ kl = (p * (lp - lq)).sum(axis=-1)
31
+ return float(np.maximum(kl, 0.0).mean())
32
+
33
+
34
+ def cosine(a: np.ndarray, b: np.ndarray) -> float:
35
+ """Mean cosine similarity in [-1, 1] over flattened vectors (1.0 == identical)."""
36
+ a = np.asarray(a, dtype=np.float64).reshape(-1)
37
+ b = np.asarray(b, dtype=np.float64).reshape(-1)
38
+ denom = (np.linalg.norm(a) * np.linalg.norm(b)) + _EPS
39
+ return float(np.dot(a, b) / denom)
40
+
41
+
42
+ def mse(a: np.ndarray, b: np.ndarray) -> float:
43
+ """Mean squared error between two arrays."""
44
+ a = np.asarray(a, dtype=np.float64)
45
+ b = np.asarray(b, dtype=np.float64)
46
+ return float(np.mean((a - b) ** 2))
47
+
48
+
49
+ def tensor_relative_error(a: np.ndarray, b: np.ndarray) -> float:
50
+ """Relative reconstruction error ``||a - b|| / (||a|| + eps)`` (Frobenius norm)."""
51
+ a = np.asarray(a, dtype=np.float64)
52
+ b = np.asarray(b, dtype=np.float64)
53
+ return float(np.linalg.norm(a - b) / (np.linalg.norm(a) + _EPS))