interp-engine 1.13.0__tar.gz → 1.13.2__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.
- {interp_engine-1.13.0 → interp_engine-1.13.2}/PKG-INFO +1 -1
- {interp_engine-1.13.0 → interp_engine-1.13.2}/docs/INTERNALS.md +13 -1
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/_demux.py +32 -2
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/mhc.py +5 -1
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/requests.py +28 -4
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/static.py +58 -8
- interp_engine-1.13.2/interp_engine/vllm_capture/static_program.py +558 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/pyproject.toml +1 -1
- interp_engine-1.13.2/tests/test_static_decode_writes_gpu.py +177 -0
- interp_engine-1.13.2/tests/test_static_program.py +207 -0
- interp_engine-1.13.2/tests/test_static_program_gpu.py +143 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_steer_math_parity.py +58 -0
- interp_engine-1.13.2/tests/test_vllm_batch_axis.py +94 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_hyper_connections.py +30 -0
- interp_engine-1.13.2/tests/test_vllm_transformers_backend_gpu.py +150 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/.gitignore +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/LICENSE +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/README.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/README.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/__init__.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/bench_spec.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/cells.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/probe.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/probe_lens_stream.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/publish.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/report_bench.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/deepseek-v4-flash-0731__eager.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/deepseek-v4-flash-0731__vllm-cudagraph.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/deepseek-v4-flash-0731__vllm-static.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/deepseek-v4-flash-0731__vllm.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/gemma-2-2b__eager.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/gemma-2-2b__vllm-cudagraph.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/gemma-2-2b__vllm-static.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/gemma-2-2b__vllm.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/llama-3.1-8b__eager.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/llama-3.1-8b__vllm-cudagraph.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/llama-3.1-8b__vllm-static.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/llama-3.1-8b__vllm.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/qwen3-4b__eager.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/qwen3-4b__vllm-cudagraph.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/qwen3-4b__vllm-static.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/qwen3-4b__vllm.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/qwen3.8-27b__eager.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/qwen3.8-27b__vllm-cudagraph.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/qwen3.8-27b__vllm-static.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results/qwen3.8-27b__vllm.json +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/results-latest.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/run_all.sh +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/run_bench.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/benchmarks/workloads.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/docs/AGENT_INTEGRATION.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/docs/ARCHITECTURE_QUIRKS.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/docs/COMPATIBILITY.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/docs/ENGINE_HOOK_MAPPINGS.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/docs/GRADIENTS.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/docs/PERFORMANCE.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/docs/PORTING.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/docs/README.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/docs/SUPPORTED_POINTS.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/docs/USAGE.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/docs/VALIDATING_A_NEW_MODEL.md +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/__init__.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/_conformance.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/_loop.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/address.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/api.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/arch.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/attn_config.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/attn_scores.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/autograd_support.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/capture.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/chat_compose.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/chat_conventions.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/chat_formatters.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/cuda_preflight.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/describe.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/directions.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/dispatch.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/facts.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/hooks.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/lens.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/lens_stream.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/lens_topk.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/load.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/mappers.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/memory.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/model.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/moe_routing.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/notebook_stdout.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/oracle.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/points.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/protocol.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/residual_basis.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/sampling.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/select.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/server/__init__.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/server/__main__.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/server/app.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/server/config.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/server/lens.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/server/runner.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/server/schemas.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/steer.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/steer_specs.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/sync.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/tokenize.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_backend.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/__init__.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/_hooks.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/_payload.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/_tp.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/_tree.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/attn.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/capture.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/graphs.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/lens/__init__.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/lens/intervene.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/lens/readout.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/lens/unembed.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/native.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/project.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_capture/steering.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/interp_engine/vllm_plugin.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/conftest.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/harness.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/model_expectations.yaml +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/synthetic_families.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_address.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_api_fixtures.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_api_generated.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_attn_config_tripwire.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_attn_probs_indexing.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_attn_scores.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_attn_z_gqa.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_autograd_support.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_bench_workloads.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_capability_refusals.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_capture_addressing.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_chat_compose.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_chat_formatters.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_chat_templates.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_core.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_cuda_preflight.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_describe.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_directions.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_doc_code_fences.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_eager_autograd.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_facts.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_family_points.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_gated_attn_out.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_gpu_sizer.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_head_contributions.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_hook_call_conventions.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_injected_system_spans.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_layer_kinds.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_lens_stream.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_lens_stream_pairing.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_load.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_logit_transform.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_mappers.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_memory.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_mlp_internals.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_model_expectations.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_moe.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_multigpu.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_multimodal_arch.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_new_models_gpu.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_no_chat_template.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_normalized_hook.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_notebook_stdout.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_oracle.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_packaging.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_padded_positions.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_parity_gpt2.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_per_layer_attn_dims.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_point_capability.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_points_registry.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_protocol.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_published_benchmarks.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_qk_norm.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_qkv_layout.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_reasoning_spans.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_release.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_resid_mid.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_residual_basis.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_sample_from_embeds.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_sampling.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_sandwich_norms.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_select.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_server.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_sliding_window_attn.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_small_models_gpu.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_static_dsv4_gpu.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_static_parity_gpu.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_static_set.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_static_warmup.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_steer_context.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_steer_ops_per_site_gpu.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_steer_reaches_generate.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_steer_scope.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_steer_specs.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_steer_stream_stack.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_sync_loop.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_sync_parity.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_unified_free_functions.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_unresolved_families.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_userless_prefix_spans.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_capture_gpu.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_capture_scales.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_engine_loop.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_graph_path.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_graphs_on_gpu.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_hook_availability.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_kv_isolation.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_new_points.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_only_families.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_padded_gpu.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_plugin.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vllm_wire_grammar.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_vocabulary_boundary.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/tests/test_worker_lens_capture_readout.py +0 -0
- {interp_engine-1.13.0 → interp_engine-1.13.2}/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.13.
|
|
3
|
+
Version: 1.13.2
|
|
4
4
|
Summary: A fast, standardized, and easy to use interpretability engine.
|
|
5
5
|
Project-URL: Homepage, https://github.com/decoderesearch/interp-engine
|
|
6
6
|
Project-URL: Repository, https://github.com/decoderesearch/interp-engine
|
|
@@ -119,7 +119,9 @@ index names the layer HF's does, which nothing checked before and which would fa
|
|
|
119
119
|
than raise. It needs `interp-engine[vllm]`, so it self-skips elsewhere; note that running it via
|
|
120
120
|
`.venv-vllm/bin/python` needs that directory on `PATH` too, because vLLM shells out to `ninja` to
|
|
121
121
|
build a sampler kernel at startup. `tests/test_vllm_wire_grammar.py` covers the same process
|
|
122
|
-
boundary on CPU, over a synthetic demux.
|
|
122
|
+
boundary on CPU, over a synthetic demux. vLLM's Transformers backend hands each hook `[1, tokens, d]`;
|
|
123
|
+
`tests/test_vllm_batch_axis.py` pins how the demux reads that on CPU, and
|
|
124
|
+
`tests/test_vllm_transformers_backend_gpu.py` runs OLMo-2 on that backend against eager. `tests/test_multigpu.py` (`-m multigpu`, two CUDA cards)
|
|
123
125
|
repeats the comparison at `num_gpus=2`: eager under accelerate's layer placement and vLLM under
|
|
124
126
|
tensor parallelism, where `vllm_capture/_tp.py` gathers the head- and neuron-sharded points across
|
|
125
127
|
ranks, against the one-card eager reference — captures, attention, steering, decode and the lens.
|
|
@@ -129,6 +131,16 @@ while the others' replies stay queued, and the next RPC consumes those — so a
|
|
|
129
131
|
took every point of a TP=8 cell with it. `resolvable_points` and `resolvable_attn` are the ask-first
|
|
130
132
|
calls; `tests/test_vllm_new_points.py` pins that they install nothing.
|
|
131
133
|
|
|
134
|
+
**Static writes inside a recorded graph.** vLLM's V2 runner records FULL decode graphs with plain
|
|
135
|
+
`torch.cuda.graph`, so a static write that Python decides at record time is replayed as "no write"
|
|
136
|
+
on every decode step. `vllm_capture/static_program.py` makes the write data instead: one Triton
|
|
137
|
+
kernel per write site reads which writer owns each row, and that writer's ops, from fixed-address
|
|
138
|
+
tables that the host refills between steps. `tests/test_static_program.py` checks the tables on CPU,
|
|
139
|
+
`tests/test_steer_math_parity.py` holds the kernel's single op form to the worker modifiers,
|
|
140
|
+
`tests/test_static_program_gpu.py` replays a graph recorded with nothing registered, and
|
|
141
|
+
`tests/test_static_decode_writes_gpu.py` requires static decode rows to match hooked vLLM for every
|
|
142
|
+
method, with and without `generated`.
|
|
143
|
+
|
|
132
144
|
**The docs are parsed, not maintained.** The point table in
|
|
133
145
|
[SUPPORTED_POINTS.md](SUPPORTED_POINTS.md) and the footnote markers in
|
|
134
146
|
[ENGINE_HOOK_MAPPINGS.md](ENGINE_HOOK_MAPPINGS.md) are read back and compared against `points.py` by
|
|
@@ -9,6 +9,7 @@ refcounting -- state manipulation only, no hook bodies.
|
|
|
9
9
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
|
+
from collections.abc import Callable
|
|
12
13
|
from typing import Any, cast
|
|
13
14
|
|
|
14
15
|
import torch
|
|
@@ -64,6 +65,10 @@ class _Demux:
|
|
|
64
65
|
self.runner_api: str | None = None
|
|
65
66
|
# Snapshot of the in-flight forward's row layout: (req_ids, seq_lens) or None.
|
|
66
67
|
self.current_meta: tuple[list[str], list[int]] | None = None
|
|
68
|
+
# Per request in ``current_meta`` order: the absolute position of its first row, or None.
|
|
69
|
+
self.current_starts: list[int] | None = None
|
|
70
|
+
# Called after each snapshot, before the forward. Static writes fill their row map here.
|
|
71
|
+
self.on_meta: list[Callable[[], None]] = []
|
|
67
72
|
# Diagnostics (see worker_demux_debug).
|
|
68
73
|
self.dbg_exec_calls = 0
|
|
69
74
|
self.dbg_last_meta: tuple[list[str], list[int]] | None = None
|
|
@@ -89,6 +94,9 @@ class _Demux:
|
|
|
89
94
|
# Installed hooks: hook site -> [handle, refcount]. Keyed by site and not by address, so
|
|
90
95
|
# two requests reading different streams of one point share a handle -- see `hook_site`.
|
|
91
96
|
self.hooks: dict[Address, list] = {}
|
|
97
|
+
# Hook site -> whether its tensor arrives with a leading batch axis of one, as seen on the
|
|
98
|
+
# last forward of more than one token (see requests._batch_axis).
|
|
99
|
+
self.batch_axis: dict[Address, bool] = {}
|
|
92
100
|
self.dev: Any = None
|
|
93
101
|
self.dt: Any = None
|
|
94
102
|
|
|
@@ -183,6 +191,22 @@ def _meta_from_v1_inputs(input_batch: object, num_scheduled_tokens: object) -> t
|
|
|
183
191
|
return _pair_meta(getattr(input_batch, "req_ids", None), num_scheduled_tokens)
|
|
184
192
|
|
|
185
193
|
|
|
194
|
+
def _starts(computed: object, meta: tuple[list[str], list[int]] | None) -> list[int] | None:
|
|
195
|
+
"""Each request's first absolute position this step, from the runner's per-request computed-token count."""
|
|
196
|
+
if meta is None or computed is None:
|
|
197
|
+
return None
|
|
198
|
+
starts = [int(x) for x in cast(Any, computed)[: len(meta[0])]]
|
|
199
|
+
return starts if len(starts) == len(meta[0]) else None
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _run_on_meta(demux: _Demux) -> None:
|
|
203
|
+
for callback in demux.on_meta:
|
|
204
|
+
try:
|
|
205
|
+
callback()
|
|
206
|
+
except Exception as exc: # noqa: BLE001 - a callback must fail closed, not stop the forward
|
|
207
|
+
demux.dbg_last_error = f"on_meta {type(exc).__name__}: {exc}"
|
|
208
|
+
|
|
209
|
+
|
|
186
210
|
def _ensure_patched(worker: object, demux: _Demux) -> None:
|
|
187
211
|
"""Patch the model runner once to snapshot each forward's row layout.
|
|
188
212
|
|
|
@@ -212,10 +236,12 @@ def _ensure_patched(worker: object, demux: _Demux) -> None:
|
|
|
212
236
|
demux.dbg_exec_calls += 1
|
|
213
237
|
try:
|
|
214
238
|
demux.current_meta = _meta_from_input_batch(input_batch)
|
|
239
|
+
demux.current_starts = _starts(getattr(input_batch, "num_computed_tokens_np", None), demux.current_meta)
|
|
215
240
|
demux.dbg_last_meta = demux.current_meta
|
|
216
241
|
except Exception as exc: # noqa: BLE001 - never break the forward on metadata errors
|
|
217
|
-
demux.current_meta = None
|
|
242
|
+
demux.current_meta = demux.current_starts = None
|
|
218
243
|
demux.dbg_last_error = f"{type(exc).__name__}: {exc}"
|
|
244
|
+
_run_on_meta(demux)
|
|
219
245
|
return input_batch
|
|
220
246
|
|
|
221
247
|
model_runner.prepare_inputs = _patched
|
|
@@ -229,10 +255,14 @@ def _ensure_patched(worker: object, demux: _Demux) -> None:
|
|
|
229
255
|
try:
|
|
230
256
|
nst = args[0] if args else kwargs.get("num_scheduled_tokens")
|
|
231
257
|
demux.current_meta = _meta_from_v1_inputs(model_runner.input_batch, nst)
|
|
258
|
+
demux.current_starts = _starts(
|
|
259
|
+
getattr(model_runner.input_batch, "num_computed_tokens_cpu", None), demux.current_meta
|
|
260
|
+
)
|
|
232
261
|
demux.dbg_last_meta = demux.current_meta
|
|
233
262
|
except Exception as exc: # noqa: BLE001 - never break the forward on metadata errors
|
|
234
|
-
demux.current_meta = None
|
|
263
|
+
demux.current_meta = demux.current_starts = None
|
|
235
264
|
demux.dbg_last_error = f"{type(exc).__name__}: {exc}"
|
|
265
|
+
_run_on_meta(demux)
|
|
236
266
|
return out
|
|
237
267
|
|
|
238
268
|
model_runner._prepare_inputs = _patched
|
|
@@ -648,9 +648,13 @@ class _MhcTaps:
|
|
|
648
648
|
detectably different from no steer at all. So the rows the recorder actually changed take the
|
|
649
649
|
re-run and every other row keeps the kernel's own output, which is also why a zero delta needs
|
|
650
650
|
no re-run: no row changed.
|
|
651
|
+
|
|
652
|
+
Inside a graph capture the host cannot read ``changed``, so the re-run is always recorded and
|
|
653
|
+
the row mask alone decides at replay.
|
|
651
654
|
"""
|
|
652
655
|
changed = (edited != stack).flatten(start_dim=1).any(dim=1)
|
|
653
|
-
|
|
656
|
+
capturing = stack.is_cuda and torch.cuda.is_current_stream_capturing()
|
|
657
|
+
if not capturing and not bool(changed.any()):
|
|
654
658
|
return fused
|
|
655
659
|
bound = signature.bind(*args, **kwargs)
|
|
656
660
|
bound.apply_defaults()
|
|
@@ -86,6 +86,32 @@ def _process_point(demux: _Demux, site: Address, full: torch.Tensor) -> torch.Te
|
|
|
86
86
|
if meta is None:
|
|
87
87
|
return full
|
|
88
88
|
req_ids, seq_lens = meta
|
|
89
|
+
if _batch_axis(demux, site, full, sum(seq_lens)):
|
|
90
|
+
rows = full[0]
|
|
91
|
+
new = _process_rows(demux, site, rows, req_ids, seq_lens)
|
|
92
|
+
return full if new is rows else new.unsqueeze(0)
|
|
93
|
+
return _process_rows(demux, site, full, req_ids, seq_lens)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _batch_axis(demux: _Demux, site: Address, full: torch.Tensor, tokens: int) -> bool:
|
|
97
|
+
"""Whether ``full`` is ``[1, tokens, ...]`` rather than tokens first.
|
|
98
|
+
|
|
99
|
+
vLLM's Transformers backend calls the HF model with a batch axis, and so do some native families
|
|
100
|
+
at attention. For a forward of more than one token the shape decides it. For one token it does
|
|
101
|
+
not: ``[1, 1, d_model]`` with a batch axis has the shape of ``[1, 1, head_dim]`` on a model with one
|
|
102
|
+
KV head, or of one token on a hyper-connection trunk. So the site keeps the answer from its last
|
|
103
|
+
forward of more than one token, and a request's prefill always comes before its decode.
|
|
104
|
+
"""
|
|
105
|
+
if full.dim() < 3 or full.shape[0] != 1:
|
|
106
|
+
return False
|
|
107
|
+
if tokens > 1:
|
|
108
|
+
demux.batch_axis[site] = full.shape[1] >= tokens
|
|
109
|
+
return demux.batch_axis.get(site, False)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _process_rows(
|
|
113
|
+
demux: _Demux, site: Address, full: torch.Tensor, req_ids: list[str], seq_lens: list[int]
|
|
114
|
+
) -> torch.Tensor:
|
|
89
115
|
if full.dim() not in (2, 3) or full.shape[0] < sum(seq_lens):
|
|
90
116
|
# Fewer rows than the layout expects (unexpected shape); skip rather than corrupt.
|
|
91
117
|
# More rows is fine: trailing padding after sum(seq_lens) is ignored by the loop.
|
|
@@ -266,10 +292,8 @@ def _mk_value_hook(demux: _Demux, site: Address):
|
|
|
266
292
|
(``_hooks.flat_value``), because a norm over ``head_dim`` is handed the per-head view.
|
|
267
293
|
|
|
268
294
|
The narrowed slice goes through ``flat_value`` too, and not only for symmetry: where vLLM leaves a
|
|
269
|
-
batch axis on the hidden state it hands the projection, the slice is ``[1, tokens, width]``,
|
|
270
|
-
|
|
271
|
-
one row and returns the tensor untouched rather than steering rows it cannot line up -- so on those
|
|
272
|
-
families this point was quietly serving nothing at all.
|
|
295
|
+
batch axis on the hidden state it hands the projection, the slice is ``[1, tokens, width]``, and
|
|
296
|
+
the packed projection's geometry is what tells that apart from a per-head view.
|
|
273
297
|
|
|
274
298
|
Either way the adjustment happens *before* steering and is undone after it, so a steer on this
|
|
275
299
|
point writes the value in the shape a capture of it reports, leaves the queries and keys of the same
|
|
@@ -50,6 +50,7 @@ from interp_engine.vllm_capture._tree import (
|
|
|
50
50
|
resolve_capture_module,
|
|
51
51
|
scale_capture,
|
|
52
52
|
)
|
|
53
|
+
from interp_engine.vllm_capture.static_program import StaticWriteProgram
|
|
53
54
|
|
|
54
55
|
#: Post-RoPE q/k/v at ``self_attn.attn``. Not a public capture point; ``capture_attention``
|
|
55
56
|
#: harvests the three roles and recomputes scores/probs.
|
|
@@ -749,6 +750,9 @@ class StaticState:
|
|
|
749
750
|
#: read-out or collect raises this rather than return a sequence with a hole in it.
|
|
750
751
|
failed: dict[str, str] = field(default_factory=dict)
|
|
751
752
|
patched_execute: bool = False
|
|
753
|
+
#: The write sites' device tables on a CUDA worker. When set, every write goes through it, so a
|
|
754
|
+
#: FULL graph replays each request's own write. None on CPU, where the Python path serves.
|
|
755
|
+
program: StaticWriteProgram | None = None
|
|
752
756
|
|
|
753
757
|
|
|
754
758
|
def _state(worker: object) -> StaticState | None:
|
|
@@ -1156,7 +1160,11 @@ def worker_install_static(worker: object) -> None:
|
|
|
1156
1160
|
if mhc_sites:
|
|
1157
1161
|
_install_mhc_static(worker, mhc_sites)
|
|
1158
1162
|
|
|
1159
|
-
|
|
1163
|
+
demux = _get_demux(worker)
|
|
1164
|
+
_ensure_patched(worker, demux)
|
|
1165
|
+
if state.writes and device.type == "cuda":
|
|
1166
|
+
state.program = StaticWriteProgram(sites=list(state.writes.values()), device=device, max_n=max_n)
|
|
1167
|
+
demux.on_meta.append(lambda: _fill_program_rows(worker))
|
|
1160
1168
|
_patch_execute_model(worker)
|
|
1161
1169
|
logger.info(
|
|
1162
1170
|
"interp-engine static: %d read site(s), %d write site(s), max_n=%d",
|
|
@@ -1166,6 +1174,25 @@ def worker_install_static(worker: object) -> None:
|
|
|
1166
1174
|
)
|
|
1167
1175
|
|
|
1168
1176
|
|
|
1177
|
+
def _fill_program_rows(worker: object) -> None:
|
|
1178
|
+
"""Point the next forward's rows at their writers. On any failure, no row is written."""
|
|
1179
|
+
static = _state(worker)
|
|
1180
|
+
program = static.program if static is not None else None
|
|
1181
|
+
if program is None:
|
|
1182
|
+
return
|
|
1183
|
+
demux = _get_demux(worker)
|
|
1184
|
+
meta = demux.current_meta
|
|
1185
|
+
try:
|
|
1186
|
+
if meta is None:
|
|
1187
|
+
program.fill_rows([], [], None, lambda rid: rid)
|
|
1188
|
+
else:
|
|
1189
|
+
program.fill_rows(meta[0], meta[1], demux.current_starts, lambda rid: _resolve_rid(demux, rid))
|
|
1190
|
+
except Exception:
|
|
1191
|
+
logger.exception("static writes: could not map this step's rows to their writers; writing none")
|
|
1192
|
+
program.fill_rows([], [], None, lambda rid: rid)
|
|
1193
|
+
raise
|
|
1194
|
+
|
|
1195
|
+
|
|
1169
1196
|
def _install_mhc_static(worker: object, mhc_sites: Sequence[_Site]) -> None:
|
|
1170
1197
|
"""Wrap the mHC kernels for every stacked static site, refusing one this model cannot serve.
|
|
1171
1198
|
|
|
@@ -1198,9 +1225,14 @@ def _static_mhc_recorder(worker: object, site: _Site):
|
|
|
1198
1225
|
if n == 0:
|
|
1199
1226
|
return tensor
|
|
1200
1227
|
static = _state(worker)
|
|
1201
|
-
|
|
1228
|
+
program = static.program if static is not None else None
|
|
1202
1229
|
live = tensor
|
|
1203
|
-
if
|
|
1230
|
+
if program is not None and program.has_site(site):
|
|
1231
|
+
# A recorded graph must hold the edit whether or not anything is registered now.
|
|
1232
|
+
if torch.cuda.is_current_stream_capturing() or not program.idle(site):
|
|
1233
|
+
live = tensor.clone()
|
|
1234
|
+
program.launch(site, live, None, n)
|
|
1235
|
+
elif (static is not None and _write_reqs_for(static, site)) or site.modify is not None or site.delta_set:
|
|
1204
1236
|
live = tensor.clone()
|
|
1205
1237
|
_apply_write(live, None, site, n, fused=False, worker=worker)
|
|
1206
1238
|
if site.buf is not None:
|
|
@@ -1637,6 +1669,12 @@ def _apply_write(
|
|
|
1637
1669
|
if n <= 0:
|
|
1638
1670
|
return
|
|
1639
1671
|
static = _state(worker) if worker is not None else None
|
|
1672
|
+
program = static.program if static is not None else None
|
|
1673
|
+
if program is not None and program.has_site(site):
|
|
1674
|
+
# A recorded graph launches the kernel on every replay; an eager forward may skip an idle site.
|
|
1675
|
+
if torch.cuda.is_current_stream_capturing() or not program.idle(site):
|
|
1676
|
+
program.launch(site, hidden, residual if fused else None, n)
|
|
1677
|
+
return
|
|
1640
1678
|
reqs = _write_reqs_for(static, site) if static is not None else []
|
|
1641
1679
|
if reqs:
|
|
1642
1680
|
_apply_demuxed_writes(hidden, residual, n, fused, worker, reqs)
|
|
@@ -1868,9 +1906,11 @@ def worker_set_static_delta(
|
|
|
1868
1906
|
) -> None:
|
|
1869
1907
|
"""Install static writes from worker specs. Zeros every write site first.
|
|
1870
1908
|
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1909
|
+
On a CUDA worker the ops go to :class:`~interp_engine.vllm_capture.static_program.StaticWriteProgram`
|
|
1910
|
+
as its global write. Without one, additive ``op="additive"`` without a scope fills the static
|
|
1911
|
+
``delta`` buffer, and every other op attaches a live ``modify`` that reads the residual each
|
|
1912
|
+
forward. ``lens_scope`` is the write's position scope: ``skip_positions``, ``prompt_len`` and
|
|
1913
|
+
``steer_generated``.
|
|
1874
1914
|
|
|
1875
1915
|
A ``stream`` disqualifies the static buffer too. The buffer is added whole to a ``[tokens,
|
|
1876
1916
|
streams, width]`` activation, so it has no way to say "this stream and not the others"; taking
|
|
@@ -1885,7 +1925,10 @@ def worker_set_static_delta(
|
|
|
1885
1925
|
worker_clear_static_delta(worker)
|
|
1886
1926
|
from interp_engine.vllm_capture.steering import _make_steer_modifiers
|
|
1887
1927
|
|
|
1888
|
-
|
|
1928
|
+
groups = _group_by_site(static, specs)
|
|
1929
|
+
if static.program is not None:
|
|
1930
|
+
static.program.set_global(groups, lens_scope)
|
|
1931
|
+
for site, group in groups.items():
|
|
1889
1932
|
assert site.delta is not None
|
|
1890
1933
|
constant = _constant_delta(group, site.delta.device, site.delta.dtype) if lens_scope is None else None
|
|
1891
1934
|
if constant is not None:
|
|
@@ -1969,8 +2012,11 @@ def worker_register_static_write(
|
|
|
1969
2012
|
skip = tuple(int(i) for i in (lens_scope.get("skip_positions") or skip))
|
|
1970
2013
|
length = int(lens_scope.get("prompt_len") or length)
|
|
1971
2014
|
generated = bool(lens_scope.get("steer_generated", False))
|
|
2015
|
+
groups = _group_by_site(static, specs)
|
|
2016
|
+
if static.program is not None:
|
|
2017
|
+
static.program.register(req_id, groups, skip=skip, prompt_len=length, generated=generated)
|
|
1972
2018
|
by_site: dict[str, _WriteReq] = {}
|
|
1973
|
-
for site, group in
|
|
2019
|
+
for site, group in groups.items():
|
|
1974
2020
|
by_site[format_address(site.address)] = _compile_write_req(
|
|
1975
2021
|
group, site, skip_positions=skip, prompt_len=length, steer_generated=generated
|
|
1976
2022
|
)
|
|
@@ -1984,6 +2030,8 @@ def worker_unregister_static_write(worker: object, req_id: str) -> None:
|
|
|
1984
2030
|
if static is None:
|
|
1985
2031
|
return
|
|
1986
2032
|
static.write_reqs.pop(req_id, None)
|
|
2033
|
+
if static.program is not None:
|
|
2034
|
+
static.program.unregister(req_id)
|
|
1987
2035
|
if req_id not in static.cap_points:
|
|
1988
2036
|
static.registered.discard(req_id)
|
|
1989
2037
|
|
|
@@ -1992,6 +2040,8 @@ def worker_clear_static_delta(worker: object) -> None:
|
|
|
1992
2040
|
static = _state(worker)
|
|
1993
2041
|
if static is None:
|
|
1994
2042
|
return
|
|
2043
|
+
if static.program is not None:
|
|
2044
|
+
static.program.clear_global()
|
|
1995
2045
|
for site in static.writes.values():
|
|
1996
2046
|
site.modify = None
|
|
1997
2047
|
site.lens_scope = None
|