interp-engine 1.2.2__tar.gz → 1.2.3__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 (170) hide show
  1. {interp_engine-1.2.2 → interp_engine-1.2.3}/PKG-INFO +3 -2
  2. {interp_engine-1.2.2 → interp_engine-1.2.3}/README.md +1 -0
  3. {interp_engine-1.2.2 → interp_engine-1.2.3}/docs/PERFORMANCE.md +9 -5
  4. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/mhc.py +39 -2
  5. {interp_engine-1.2.2 → interp_engine-1.2.3}/pyproject.toml +11 -5
  6. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_vllm_hyper_connections.py +19 -1
  7. {interp_engine-1.2.2 → interp_engine-1.2.3}/.gitignore +0 -0
  8. {interp_engine-1.2.2 → interp_engine-1.2.3}/LICENSE +0 -0
  9. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/README.md +0 -0
  10. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/__init__.py +0 -0
  11. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/bench_spec.py +0 -0
  12. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/cells.py +0 -0
  13. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/probe.py +0 -0
  14. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/publish.py +0 -0
  15. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/report_bench.py +0 -0
  16. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/deepseek-v4-flash-0731__eager.json +0 -0
  17. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/deepseek-v4-flash-0731__vllm-cudagraph.json +0 -0
  18. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/deepseek-v4-flash-0731__vllm-dspark-cudagraph.json +0 -0
  19. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/deepseek-v4-flash-0731__vllm-dspark.json +0 -0
  20. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/deepseek-v4-flash-0731__vllm-freeze.json +0 -0
  21. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/deepseek-v4-flash-0731__vllm.json +0 -0
  22. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/gemma-2-2b__eager.json +0 -0
  23. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/gemma-2-2b__vllm-cudagraph.json +0 -0
  24. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/gemma-2-2b__vllm-freeze.json +0 -0
  25. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/gemma-2-2b__vllm.json +0 -0
  26. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/llama-3.1-8b__eager.json +0 -0
  27. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/llama-3.1-8b__vllm-cudagraph.json +0 -0
  28. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/llama-3.1-8b__vllm-freeze.json +0 -0
  29. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/llama-3.1-8b__vllm.json +0 -0
  30. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/qwen3-4b__eager.json +0 -0
  31. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/qwen3-4b__vllm-cudagraph.json +0 -0
  32. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/qwen3-4b__vllm-freeze.json +0 -0
  33. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/qwen3-4b__vllm.json +0 -0
  34. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/qwen3.8-27b__eager.json +0 -0
  35. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/qwen3.8-27b__vllm-cudagraph.json +0 -0
  36. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/qwen3.8-27b__vllm-freeze.json +0 -0
  37. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results/qwen3.8-27b__vllm.json +0 -0
  38. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/results-latest.md +0 -0
  39. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/run_all.sh +0 -0
  40. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/run_bench.py +0 -0
  41. {interp_engine-1.2.2 → interp_engine-1.2.3}/benchmarks/workloads.py +0 -0
  42. {interp_engine-1.2.2 → interp_engine-1.2.3}/docs/AGENT_INTEGRATION.md +0 -0
  43. {interp_engine-1.2.2 → interp_engine-1.2.3}/docs/ARCHITECTURE_QUIRKS.md +0 -0
  44. {interp_engine-1.2.2 → interp_engine-1.2.3}/docs/COMPATIBILITY.md +0 -0
  45. {interp_engine-1.2.2 → interp_engine-1.2.3}/docs/ENGINE_HOOK_MAPPINGS.md +0 -0
  46. {interp_engine-1.2.2 → interp_engine-1.2.3}/docs/GRADIENTS.md +0 -0
  47. {interp_engine-1.2.2 → interp_engine-1.2.3}/docs/INTERNALS.md +0 -0
  48. {interp_engine-1.2.2 → interp_engine-1.2.3}/docs/PORTING.md +0 -0
  49. {interp_engine-1.2.2 → interp_engine-1.2.3}/docs/README.md +0 -0
  50. {interp_engine-1.2.2 → interp_engine-1.2.3}/docs/SUPPORTED_POINTS.md +0 -0
  51. {interp_engine-1.2.2 → interp_engine-1.2.3}/docs/USAGE.md +0 -0
  52. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/__init__.py +0 -0
  53. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/_loop.py +0 -0
  54. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/address.py +0 -0
  55. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/arch.py +0 -0
  56. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/attn_config.py +0 -0
  57. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/attn_scores.py +0 -0
  58. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/autograd_support.py +0 -0
  59. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/capture.py +0 -0
  60. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/chat_compose.py +0 -0
  61. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/chat_conventions.py +0 -0
  62. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/cuda_preflight.py +0 -0
  63. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/dispatch.py +0 -0
  64. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/facts.py +0 -0
  65. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/hooks.py +0 -0
  66. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/lens.py +0 -0
  67. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/load.py +0 -0
  68. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/mappers.py +0 -0
  69. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/model.py +0 -0
  70. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/moe_routing.py +0 -0
  71. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/points.py +0 -0
  72. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/protocol.py +0 -0
  73. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/residual_basis.py +0 -0
  74. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/select.py +0 -0
  75. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/steer.py +0 -0
  76. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/steer_specs.py +0 -0
  77. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/sync.py +0 -0
  78. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/tokenize.py +0 -0
  79. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_backend.py +0 -0
  80. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/__init__.py +0 -0
  81. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/_demux.py +0 -0
  82. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/_hooks.py +0 -0
  83. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/_payload.py +0 -0
  84. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/_tree.py +0 -0
  85. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/attn.py +0 -0
  86. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/capture.py +0 -0
  87. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/freeze.py +0 -0
  88. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/graphs.py +0 -0
  89. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/lens/__init__.py +0 -0
  90. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/lens/intervene.py +0 -0
  91. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/lens/readout.py +0 -0
  92. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/lens/unembed.py +0 -0
  93. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/native.py +0 -0
  94. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/requests.py +0 -0
  95. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_capture/steering.py +0 -0
  96. {interp_engine-1.2.2 → interp_engine-1.2.3}/interp_engine/vllm_plugin.py +0 -0
  97. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/conftest.py +0 -0
  98. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/harness.py +0 -0
  99. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/model_expectations.yaml +0 -0
  100. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/synthetic_families.py +0 -0
  101. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_address.py +0 -0
  102. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_attn_config_tripwire.py +0 -0
  103. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_attn_probs_indexing.py +0 -0
  104. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_attn_scores.py +0 -0
  105. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_attn_z_gqa.py +0 -0
  106. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_autograd_support.py +0 -0
  107. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_bench_workloads.py +0 -0
  108. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_capability_refusals.py +0 -0
  109. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_capture_addressing.py +0 -0
  110. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_chat_compose.py +0 -0
  111. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_chat_templates.py +0 -0
  112. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_core.py +0 -0
  113. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_cuda_preflight.py +0 -0
  114. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_doc_code_fences.py +0 -0
  115. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_eager_autograd.py +0 -0
  116. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_facts.py +0 -0
  117. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_family_points.py +0 -0
  118. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_freeze_dsv4_gpu.py +0 -0
  119. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_freeze_parity_gpu.py +0 -0
  120. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_freeze_set.py +0 -0
  121. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_freeze_warmup.py +0 -0
  122. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_gated_attn_out.py +0 -0
  123. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_head_contributions.py +0 -0
  124. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_hook_call_conventions.py +0 -0
  125. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_layer_kinds.py +0 -0
  126. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_load.py +0 -0
  127. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_logit_transform.py +0 -0
  128. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_mappers.py +0 -0
  129. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_mlp_internals.py +0 -0
  130. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_model_expectations.py +0 -0
  131. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_moe.py +0 -0
  132. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_multimodal_arch.py +0 -0
  133. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_new_models_gpu.py +0 -0
  134. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_no_chat_template.py +0 -0
  135. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_normalized_hook.py +0 -0
  136. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_packaging.py +0 -0
  137. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_parity_gpt2.py +0 -0
  138. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_per_layer_attn_dims.py +0 -0
  139. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_points_registry.py +0 -0
  140. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_protocol.py +0 -0
  141. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_published_benchmarks.py +0 -0
  142. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_qk_norm.py +0 -0
  143. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_qkv_layout.py +0 -0
  144. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_reasoning_spans.py +0 -0
  145. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_release.py +0 -0
  146. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_resid_mid.py +0 -0
  147. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_residual_basis.py +0 -0
  148. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_sandwich_norms.py +0 -0
  149. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_select.py +0 -0
  150. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_sliding_window_attn.py +0 -0
  151. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_small_models_gpu.py +0 -0
  152. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_steer_context.py +0 -0
  153. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_steer_math_parity.py +0 -0
  154. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_sync_loop.py +0 -0
  155. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_sync_parity.py +0 -0
  156. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_unified_free_functions.py +0 -0
  157. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_unresolved_families.py +0 -0
  158. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_vllm_capture_gpu.py +0 -0
  159. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_vllm_capture_scales.py +0 -0
  160. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_vllm_graph_path.py +0 -0
  161. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_vllm_graphs_on_gpu.py +0 -0
  162. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_vllm_hook_availability.py +0 -0
  163. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_vllm_kv_isolation.py +0 -0
  164. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_vllm_new_points.py +0 -0
  165. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_vllm_only_families.py +0 -0
  166. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_vllm_plugin.py +0 -0
  167. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_vllm_wire_grammar.py +0 -0
  168. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_vocabulary_boundary.py +0 -0
  169. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_worker_lens_capture_readout.py +0 -0
  170. {interp_engine-1.2.2 → interp_engine-1.2.3}/tests/test_worker_lens_readout.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: interp-engine
3
- Version: 1.2.2
3
+ Version: 1.2.3
4
4
  Summary: A fast, standardized interpretability engine that supports most modern models and architectures. Powers Neuronpedia.
5
5
  Project-URL: Homepage, https://github.com/decoderesearch/interp-engine
6
6
  Project-URL: Repository, https://github.com/decoderesearch/interp-engine
@@ -26,7 +26,7 @@ Provides-Extra: quant
26
26
  Requires-Dist: accelerate>=1.0; extra == 'quant'
27
27
  Requires-Dist: kernels<0.17.0,>=0.15.2; extra == 'quant'
28
28
  Provides-Extra: vllm
29
- Requires-Dist: vllm>=0.25.1; (sys_platform == 'linux') and extra == 'vllm'
29
+ Requires-Dist: vllm>=0.27.1; (sys_platform == 'linux') and extra == 'vllm'
30
30
  Description-Content-Type: text/markdown
31
31
 
32
32
  # interp-engine
@@ -38,6 +38,7 @@ Description-Content-Type: text/markdown
38
38
  🔗 <a href="https://interp-engine.org"><strong>interp-engine.org</strong></a>
39
39
  </p>
40
40
 
41
+
41
42
  `interp-engine` is an interpretability engine that is fast (>40x tok/s vs HF eager), standardized (34 'points'/addresses across architectures), and easy to use and debug. It powers all of [Neuronpedia](https://neuronpedia.org)'s inference and is checked for accuracy against HF Transformers and other engines.
42
43
 
43
44
  <p align="center">
@@ -7,6 +7,7 @@
7
7
  🔗 <a href="https://interp-engine.org"><strong>interp-engine.org</strong></a>
8
8
  </p>
9
9
 
10
+
10
11
  `interp-engine` is an interpretability engine that is fast (>40x tok/s vs HF eager), standardized (34 'points'/addresses across architectures), and easy to use and debug. It powers all of [Neuronpedia](https://neuronpedia.org)'s inference and is checked for accuracy against HF Transformers and other engines.
11
12
 
12
13
  <p align="center">
@@ -42,13 +42,17 @@ every new upstream flag into an engine change.
42
42
 
43
43
  ### The vLLM version is a floor, not a ceiling
44
44
 
45
- `interp-engine[vllm]` declares `vllm>=0.25.1` on Linux and no upper bound. Read that as **the oldest
45
+ `interp-engine[vllm]` declares `vllm>=0.27.1` on Linux and no upper bound. Read that as **the oldest
46
46
  version we have evidence for**, not the version to run:
47
47
 
48
- - **The floor is measured, not guessed.** 0.25.1 is the oldest version the engine has been exercised
49
- on. The current sweep in [`benchmarks/results-latest.md`](../benchmarks/results-latest.md) ran on
50
- **0.26.0**, which is also what `apps/inference` and `apps/nla` resolve to being ahead of the floor
51
- is the normal state, not drift.
48
+ - **The floor is measured, not guessed.** 0.27.1 is the version the DeepSeek-V4-Flash-0731
49
+ cross-engine comparison scored, and the oldest the engine is supported on. The performance sweep in
50
+ [`benchmarks/results-latest.md`](../benchmarks/results-latest.md) ran on **0.26.0**, one below
51
+ being ahead of the floor is the normal state, not drift.
52
+ - **This floor is load-bearing, not hygiene.** It was 0.25.1 until `vllm_capture/mhc.py` needed
53
+ `mhc_pre_broadcast_tilelang`, which arrived in 0.26.0. Below that, every DeepSeek-V4
54
+ hyper-connection point is refused at install, and since `FREEZE_POINTS=auto` selects
55
+ `resid_streams` on such a trunk, the pod does not load at all.
52
56
  - **There is deliberately no cap.** vLLM moves fast and a `<` bound would make every upstream release
53
57
  an engine release; a lock file is the right place to pin a deployment, and both apps have one. The
54
58
  version an app runs is whatever its `uv.lock` resolved, which is normally newer than this floor.
@@ -308,6 +308,29 @@ def _kernel_module(layer: torch.nn.Module) -> ModuleType | None:
308
308
  return module
309
309
 
310
310
 
311
+ def _missing_kernels(layer: torch.nn.Module) -> tuple[str, ...]:
312
+ """Which of :data:`KERNEL_NAMES` the layer's defining module does not have.
313
+
314
+ Separated from :func:`_kernel_module`, which only answers yes or no, because *which* names are
315
+ absent is the difference between the two reasons a model gets refused: none of them means the
316
+ wrong platform tree, some of them means the right tree on a vLLM that predates a kernel.
317
+ """
318
+ module = sys.modules.get(type(layer).__module__)
319
+ if module is None:
320
+ return KERNEL_NAMES
321
+ return tuple(name for name in KERNEL_NAMES if not hasattr(module, name))
322
+
323
+
324
+ def _vllm_version() -> str:
325
+ """The running vLLM's version for an error message, or a placeholder. Never raises."""
326
+ try:
327
+ from importlib.metadata import version
328
+
329
+ return version("vllm")
330
+ except Exception: # pragma: no cover - a diagnostic string is not worth a failure mode
331
+ return "unknown"
332
+
333
+
311
334
  def _mhc_layers(model: torch.nn.Module) -> list[tuple[int, torch.nn.Module]]:
312
335
  layers = _get_layers(model)
313
336
  return [(i, layer) for i, layer in enumerate(layers) if hasattr(layer, _MHC_MARKER_PARAM)]
@@ -332,9 +355,23 @@ def unavailable_reason(model: torch.nn.Module, name: str, layer: int | None = No
332
355
  )
333
356
  module = _kernel_module(mhc[0][1])
334
357
  if module is None:
358
+ layer_type = type(mhc[0][1])
359
+ missing = _missing_kernels(mhc[0][1])
360
+ if len(missing) < len(KERNEL_NAMES):
361
+ # Some names are there and some are not, so this IS the tree that calls the kernels by
362
+ # name -- it is just an older one than the engine was written against. Said separately
363
+ # from the tree refusal below because the fix is a vLLM upgrade rather than a port, and
364
+ # the two are indistinguishable from the point's name alone.
365
+ return (
366
+ f"{layer_type.__name__} (from {layer_type.__module__}) calls the tilelang mHC "
367
+ f"kernels by name, but {', '.join(missing)} is not in its namespace and this point "
368
+ f"is served by intercepting all of {', '.join(KERNEL_NAMES)} there. That is a vLLM "
369
+ f"older than this engine supports, not the wrong platform tree: the installed vLLM "
370
+ f"is {_vllm_version()} and interp-engine declares vllm>=0.27.1. Upgrade vLLM."
371
+ )
335
372
  return (
336
- f"{type(mhc[0][1]).__name__} does not call vLLM's tilelang mHC kernels by name, so there "
337
- "is nothing to wrap: this point is served by intercepting "
373
+ f"{layer_type.__name__} (from {layer_type.__module__}) does not call vLLM's tilelang mHC "
374
+ "kernels by name, so there is nothing to wrap: this point is served by intercepting "
338
375
  f"{', '.join(KERNEL_NAMES)} in the model module's namespace, which only "
339
376
  "models/deepseek_v4/nvidia/model.py does. The amd/ and xpu/ trees instantiate "
340
377
  "MHCPreOp/MHCPostOp/MHCFusedPostPreOp as modules and apply the block norm separately, so "
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "interp-engine"
3
- version = "1.2.2"
3
+ version = "1.2.3"
4
4
  description = "A fast, standardized interpretability engine that supports most modern models and architectures. Powers Neuronpedia."
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -46,9 +46,15 @@ dev = [
46
46
  # EagerModel core must install on macOS/CPU). Apps that actually run the vLLM backend depend on
47
47
  # `interp-engine[vllm]` so the version pin lives here, next to the code that imports it.
48
48
  #
49
- # A FLOOR, not a ceiling, and deliberately uncapped: 0.25.1 is the oldest version there is evidence
50
- # for (the whole benchmark sweep ran on it), not the version to run. Raise it only when engine code
51
- # needs a newer API, and name that code. See docs/PERFORMANCE.md, "The vLLM version is a floor, not a
49
+ # A FLOOR, not a ceiling, and deliberately uncapped: 0.27.1 is the oldest version there is evidence
50
+ # for, not the version to run. Raise it only when engine code needs a newer API, and name that code.
51
+ # Raised from 0.25.1 for `vllm_capture/mhc.py`, which reaches DeepSeek-V4's hyper-connection points
52
+ # by patching all four tilelang mHC kernels in the model module's namespace (`KERNEL_NAMES`). One of
53
+ # them, `mhc_pre_broadcast_tilelang`, does not exist before 0.26.0, so on 0.25.x every mHC point --
54
+ # `resid_streams` included, which `FREEZE_POINTS=auto` selects on such a trunk -- is refused at
55
+ # install and the pod fails to load. 0.27.1 rather than 0.26.0 because that is the version the
56
+ # DeepSeek-V4-Flash-0731 cross-engine comparison actually scored (validator/comparison/results/
57
+ # deepseek-ai/DeepSeek-V4-Flash-0731/). See docs/PERFORMANCE.md, "The vLLM version is a floor, not a
52
58
  # ceiling", for why there is no upper bound and what to do when an upstream release breaks capture.
53
59
  #
54
60
  # Why this is an extra and NOT a marker-gated base dependency, which is the recurring suggestion:
@@ -66,7 +72,7 @@ dev = [
66
72
  # The `sys_platform` marker below is the one axis a marker CAN answer: it makes the extra itself a
67
73
  # no-op on macOS rather than an error, so `[vllm]` is safe to ask for unconditionally.
68
74
  vllm = [
69
- "vllm>=0.25.1; sys_platform == 'linux'",
75
+ "vllm>=0.27.1; sys_platform == 'linux'",
70
76
  ]
71
77
  # MXFP4-quantized models (e.g. gpt-oss) and block-FP8 ones (DeepSeek-V4-Flash) need the Triton kernel
72
78
  # loader, which in turn needs huggingface-hub>=1.0 / transformers>=5. Missing it is not always an
@@ -759,12 +759,30 @@ def test_a_tree_that_does_not_call_these_kernels_by_name_is_refused_with_the_alt
759
759
  norm separately, so there is nothing to wrap -- and every one of these points is an ordinary module
760
760
  output there. Unwired rather than unreachable, and the refusal has to say which."""
761
761
  trunk = _HyperTrunk()
762
- monkeypatch.delattr(sys.modules[__name__], "mhc_post_tilelang")
762
+ for name in KERNEL_NAMES:
763
+ monkeypatch.delattr(sys.modules[__name__], name)
763
764
  reason = unavailable_reason(trunk, "resid_streams", 0)
764
765
  assert reason is not None
765
766
  assert "amd/ and xpu/" in reason and "module output" in reason
766
767
 
767
768
 
769
+ def test_a_vllm_too_old_for_one_kernel_is_refused_as_a_version_and_not_as_a_tree(monkeypatch):
770
+ """The refusal these two tests share a branch with is the one that cost a pod an afternoon.
771
+
772
+ `mhc_pre_broadcast_tilelang` arrived in vLLM 0.26.0, so on 0.25.x the NVIDIA tree calls three of
773
+ these four by name and the wrapper -- which needs all four -- backs out. Answering that with the
774
+ amd/xpu text sends the reader to a platform port when the fix is `pip install -U vllm`, so a
775
+ module that has *some* of the names has to be told apart from one that has none.
776
+ """
777
+ trunk = _HyperTrunk()
778
+ monkeypatch.delattr(sys.modules[__name__], "mhc_pre_broadcast_tilelang")
779
+ reason = unavailable_reason(trunk, "resid_streams", 0)
780
+ assert reason is not None
781
+ assert "mhc_pre_broadcast_tilelang" in reason, "the reader has to be told which name is missing"
782
+ assert "Upgrade vLLM" in reason
783
+ assert "amd/" not in reason, "a version skew is not a platform-tree problem"
784
+
785
+
768
786
  def test_the_last_layers_stack_is_refused_when_a_draft_model_shares_the_closing_call():
769
787
  """EAGLE reconstructs auxiliary hidden states with the same `mhc_post` function, so which call
770
788
  completed the trunk stops being decidable. Refused rather than guessed -- and only for the layer
File without changes
File without changes