mtplx 2.2.0__tar.gz → 2.4.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 (417) hide show
  1. {mtplx-2.2.0 → mtplx-2.4.0}/CHANGELOG.md +189 -0
  2. {mtplx-2.2.0 → mtplx-2.4.0}/NOTICE +4 -0
  3. {mtplx-2.2.0 → mtplx-2.4.0}/PKG-INFO +23 -3
  4. {mtplx-2.2.0 → mtplx-2.4.0}/README.md +20 -1
  5. mtplx-2.4.0/mtplx/a3b_compiled_target_prefix.py +981 -0
  6. mtplx-2.4.0/mtplx/a3b_whole_moe.py +1224 -0
  7. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/artifacts.py +121 -8
  8. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/backends/descriptors.py +66 -2
  9. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/backends/hy_v3_mtp.py +3 -3
  10. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/backends/registry.py +83 -11
  11. mtplx-2.4.0/mtplx/batched_decode.py +1322 -0
  12. mtplx-2.4.0/mtplx/benchmarks/code_eval.py +405 -0
  13. mtplx-2.4.0/mtplx/benchmarks/programming_prompts.py +246 -0
  14. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/cache_state.py +198 -0
  15. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/cli.py +18 -5
  16. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/commands/public.py +260 -54
  17. mtplx-2.4.0/mtplx/compile_state.py +39 -0
  18. mtplx-2.4.0/mtplx/compiled_forward.py +144 -0
  19. mtplx-2.4.0/mtplx/constrained.py +544 -0
  20. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/context_copy.py +39 -2
  21. mtplx-2.2.0/mtplx/dashboard/_static/assets/index-COqTDxL-.js → mtplx-2.4.0/mtplx/dashboard/_static/assets/index-CRP90ECi.js +36 -36
  22. mtplx-2.4.0/mtplx/dashboard/_static/assets/index-DYvLRZ33.css +1 -0
  23. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/dashboard/_static/index.html +2 -2
  24. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/deepseek_mtp_patch.py +29 -1
  25. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/engine_session.py +77 -5
  26. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/gdn_capture.py +895 -2
  27. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/generation.py +1141 -161
  28. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/graphbank.py +23 -8
  29. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/hf_loader.py +173 -5
  30. mtplx-2.4.0/mtplx/hy_v3_mtp_patch.py +355 -0
  31. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kernel_selfcheck.py +275 -1
  32. mtplx-2.4.0/mtplx/kernels/a3b_whole_moe.py +2673 -0
  33. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kernels/fused_norm.py +116 -3
  34. mtplx-2.4.0/mtplx/kernels/laguna_decode.py +1224 -0
  35. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kv_quant.py +19 -12
  36. mtplx-2.4.0/mtplx/laguna_compiled_step.py +829 -0
  37. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/loop_guard.py +16 -3
  38. mtplx-2.4.0/mtplx/metadata_scrub.py +125 -0
  39. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/mimo_mtp_patch.py +30 -1
  40. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/model_catalog.py +17 -0
  41. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/model_scheduler.py +28 -2
  42. mtplx-2.4.0/mtplx/models/__init__.py +1 -0
  43. mtplx-2.4.0/mtplx/models/laguna.py +529 -0
  44. mtplx-2.4.0/mtplx/models/laguna_config.py +299 -0
  45. mtplx-2.4.0/mtplx/models/laguna_fused.py +1336 -0
  46. mtplx-2.4.0/mtplx/moe_packed_projections.py +396 -0
  47. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/mtp_patch.py +9 -2
  48. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/nemotron_h_mtp_patch.py +26 -1
  49. mtplx-2.4.0/mtplx/optimization_profiles.py +222 -0
  50. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/profiles.py +3 -0
  51. mtplx-2.4.0/mtplx/progress_heartbeat.py +23 -0
  52. mtplx-2.4.0/mtplx/proj_quant.py +156 -0
  53. mtplx-2.4.0/mtplx/qwen_row_owned_router.py +678 -0
  54. mtplx-2.4.0/mtplx/ragged_attention.py +105 -0
  55. mtplx-2.4.0/mtplx/ragged_kv_cache.py +557 -0
  56. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/reasoning_codecs.py +1 -1
  57. mtplx-2.4.0/mtplx/roofline_profile.py +270 -0
  58. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/runtime.py +463 -28
  59. mtplx-2.4.0/mtplx/runtime_options.py +210 -0
  60. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/server/dashboard_state.py +10 -2
  61. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/server/omlx_bridge/tool_calling.py +122 -3
  62. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/server/openai.py +1127 -101
  63. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/session_bank.py +8 -4
  64. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/thermal.py +253 -32
  65. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/thermal_sidecar.py +12 -5
  66. mtplx-2.4.0/mtplx/thinking_guard.py +442 -0
  67. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/version.py +2 -2
  68. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx.egg-info/PKG-INFO +23 -3
  69. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx.egg-info/SOURCES.txt +60 -2
  70. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx.egg-info/requires.txt +2 -1
  71. {mtplx-2.2.0 → mtplx-2.4.0}/pyproject.toml +6 -2
  72. mtplx-2.4.0/scripts/code_eval_gate.py +706 -0
  73. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/pillar_gate_qa.py +25 -12
  74. mtplx-2.4.0/scripts/session_forensics.py +439 -0
  75. mtplx-2.4.0/scripts/walltime-lab/run_project.py +227 -0
  76. mtplx-2.4.0/tests/test_a3b_compiled_target_prefix.py +769 -0
  77. mtplx-2.4.0/tests/test_a3b_whole_moe.py +1584 -0
  78. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_artifacts.py +312 -0
  79. mtplx-2.4.0/tests/test_batched_decode.py +1197 -0
  80. mtplx-2.4.0/tests/test_bracket_tool_rescue.py +69 -0
  81. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_cache_state.py +198 -0
  82. mtplx-2.4.0/tests/test_code_eval.py +259 -0
  83. mtplx-2.4.0/tests/test_code_eval_gate.py +547 -0
  84. mtplx-2.4.0/tests/test_compile_state.py +46 -0
  85. mtplx-2.4.0/tests/test_compiled_ar_wiring.py +116 -0
  86. mtplx-2.4.0/tests/test_compiled_forward.py +139 -0
  87. mtplx-2.4.0/tests/test_constrained.py +739 -0
  88. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_context_copy_stats.py +107 -0
  89. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_dashboard_endpoints.py +15 -0
  90. mtplx-2.4.0/tests/test_env_flag_parsing.py +346 -0
  91. mtplx-2.4.0/tests/test_gdn_postconv_fusion.py +503 -0
  92. mtplx-2.4.0/tests/test_gdn_postconv_impl_gate.py +228 -0
  93. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_generation_sustained.py +132 -4
  94. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_graphbank_compiled_verify.py +417 -8
  95. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_hf_loader.py +165 -0
  96. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_hy_v3_mtp_backend.py +36 -5
  97. mtplx-2.4.0/tests/test_hy_v3_mtp_graft.py +209 -0
  98. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_kernel_selfcheck.py +150 -1
  99. mtplx-2.4.0/tests/test_laguna_compiled_step.py +1189 -0
  100. mtplx-2.4.0/tests/test_laguna_fused.py +1179 -0
  101. mtplx-2.4.0/tests/test_laguna_model.py +1122 -0
  102. mtplx-2.4.0/tests/test_metadata_scrub.py +153 -0
  103. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_metal_memory_caps.py +94 -0
  104. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_model_catalog.py +4 -4
  105. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_model_scheduler.py +25 -0
  106. mtplx-2.4.0/tests/test_moe_force_unsorted.py +293 -0
  107. mtplx-2.4.0/tests/test_moe_packed_projections.py +353 -0
  108. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_mtp_patch.py +72 -0
  109. mtplx-2.4.0/tests/test_mtp_payload_guards.py +65 -0
  110. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_no_mlx_imports.py +78 -19
  111. mtplx-2.4.0/tests/test_omlx_bridge.py +334 -0
  112. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_openai_bridge.py +6 -4
  113. mtplx-2.4.0/tests/test_optimization_profiles.py +63 -0
  114. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_postcommit_prefix_reuse.py +6 -4
  115. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_postcommit_wait_integration.py +58 -0
  116. mtplx-2.4.0/tests/test_proj_quant.py +107 -0
  117. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_public_cli.py +339 -1
  118. mtplx-2.4.0/tests/test_qwen_row_owned_router.py +578 -0
  119. mtplx-2.4.0/tests/test_ragged_kv_cache.py +760 -0
  120. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_reasoning_stream_split.py +23 -1
  121. mtplx-2.4.0/tests/test_runtime_kpis.py +136 -0
  122. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_server_openai.py +686 -20
  123. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_session_bank.py +22 -0
  124. mtplx-2.4.0/tests/test_snapshot_free_rejection_repair.py +123 -0
  125. mtplx-2.4.0/tests/test_stream_guard_env.py +50 -0
  126. mtplx-2.4.0/tests/test_stream_stall_watchdog.py +66 -0
  127. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_thermal.py +235 -0
  128. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_thermal_sidecar.py +25 -0
  129. mtplx-2.4.0/tests/test_thinking_guard.py +275 -0
  130. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_tool_aware_stream_translator.py +73 -4
  131. mtplx-2.4.0/tests/test_tool_nested_args_streaming.py +363 -0
  132. mtplx-2.2.0/mtplx/dashboard/_static/assets/index-BYd4MFty.css +0 -1
  133. mtplx-2.2.0/mtplx/hy_v3_mtp_patch.py +0 -165
  134. mtplx-2.2.0/mtplx/runtime_options.py +0 -88
  135. mtplx-2.2.0/tests/test_omlx_bridge.py +0 -139
  136. mtplx-2.2.0/tests/test_runtime_kpis.py +0 -64
  137. {mtplx-2.2.0 → mtplx-2.4.0}/CITATION.cff +0 -0
  138. {mtplx-2.2.0 → mtplx-2.4.0}/LICENSE +0 -0
  139. {mtplx-2.2.0 → mtplx-2.4.0}/MANIFEST.in +0 -0
  140. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/__init__.py +0 -0
  141. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/adaptive.py +0 -0
  142. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/app_settings.py +0 -0
  143. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/attention_context.py +0 -0
  144. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/attention_split.py +0 -0
  145. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/backends/__init__.py +0 -0
  146. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/backends/deepseek_mtp.py +0 -0
  147. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/backends/gemma4_assistant.py +0 -0
  148. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/backends/glm_mtp.py +0 -0
  149. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/backends/mimo_mtp.py +0 -0
  150. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/backends/nemotron_h_mtp.py +0 -0
  151. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/backends/qwen3_next.py +0 -0
  152. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/backends/step3p5_mtp.py +0 -0
  153. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/batching/__init__.py +0 -0
  154. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/batching/admission.py +0 -0
  155. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/batching/buckets.py +0 -0
  156. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/batching/scheduler.py +0 -0
  157. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/batching/state.py +0 -0
  158. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/__init__.py +0 -0
  159. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/prompts/aime_2026.jsonl +0 -0
  160. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/prompts/calibration_coding.jsonl +0 -0
  161. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/prompts/default.jsonl +0 -0
  162. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/prompts/flappy.jsonl +0 -0
  163. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/prompts/long_code.jsonl +0 -0
  164. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/prompts/long_code_uncapped.jsonl +0 -0
  165. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/prompts/python_modules_long.jsonl +0 -0
  166. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/__init__.py +0 -0
  167. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/aime.py +0 -0
  168. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/batch_equivalence.py +0 -0
  169. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/capture_commit_equivalence.py +0 -0
  170. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/competitor_baselines.py +0 -0
  171. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/contract_probe.py +0 -0
  172. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/harness.py +0 -0
  173. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/mtp1_gate.py +0 -0
  174. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/mtp1_sampler_smoke.py +0 -0
  175. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/mtp_adaptive.py +0 -0
  176. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/mtp_chain_probe.py +0 -0
  177. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/mtp_depth_grid.py +0 -0
  178. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/mtp_depth_sweep.py +0 -0
  179. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/mtp_tree_probe.py +0 -0
  180. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/multi_qmv_probe.py +0 -0
  181. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/preflight.py +0 -0
  182. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/runtime_smoke.py +0 -0
  183. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/session_bank.py +0 -0
  184. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/truth.py +0 -0
  185. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/verify_profile.py +0 -0
  186. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/verify_qmm_probe.py +0 -0
  187. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/runners/verify_ratio.py +0 -0
  188. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/schema.py +0 -0
  189. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/validators/__init__.py +0 -0
  190. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/validators/aime.py +0 -0
  191. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/benchmarks/validators/basic.py +0 -0
  192. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/block_attention.py +0 -0
  193. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/cache_bank/__init__.py +0 -0
  194. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/cache_bank/codec.py +0 -0
  195. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/cache_bank/cold_tier.py +0 -0
  196. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/chat_encoding.py +0 -0
  197. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/commands/__init__.py +0 -0
  198. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/commands/forge.py +0 -0
  199. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/compressed_tensors.py +0 -0
  200. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/config.py +0 -0
  201. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/constants.py +0 -0
  202. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/correctors/__init__.py +0 -0
  203. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/correctors/diagonal_affine.py +0 -0
  204. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/correctors/low_rank.py +0 -0
  205. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/daemon_client.py +0 -0
  206. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/dashboard/__init__.py +0 -0
  207. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/default_models.py +0 -0
  208. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/diagnostics.py +0 -0
  209. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/draft_lm_head.py +0 -0
  210. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/draft_sampling.py +0 -0
  211. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/env.py +0 -0
  212. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/errors.py +0 -0
  213. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/expert_layout.py +0 -0
  214. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/fan_mode.py +0 -0
  215. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/fast_sampling.py +0 -0
  216. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/gemma4_pair.py +0 -0
  217. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/glm_mtp_patch.py +0 -0
  218. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/hardware.py +0 -0
  219. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kernels/__init__.py +0 -0
  220. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kernels/copy_leaf.py +0 -0
  221. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kernels/lm_head_topk.py +0 -0
  222. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kernels/logits_topk.py +0 -0
  223. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kernels/native_gdn_tail.py +0 -0
  224. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kernels/sdpa_2pass.py +0 -0
  225. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kernels/sdpa_2pass_paged.py +0 -0
  226. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kernels/sdpa_2pass_paged_q8.py +0 -0
  227. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kernels/sdpa_gqa_packed.py +0 -0
  228. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kernels/verify_mlp_fused.py +0 -0
  229. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kpi/__init__.py +0 -0
  230. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kpi/reference_vllm.py +0 -0
  231. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/kpi/runtime_kpis.py +0 -0
  232. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/mtp_activation_stats.py +0 -0
  233. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/mtp_adapters.py +0 -0
  234. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/native_mlp.py +0 -0
  235. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/nax_verify.py +0 -0
  236. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/opencode.py +0 -0
  237. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/pi.py +0 -0
  238. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/prefill_bench.py +0 -0
  239. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/proposal_reranker.py +0 -0
  240. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/qwen3_5_mtp_patch.py +0 -0
  241. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/sampling.py +0 -0
  242. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/server/__init__.py +0 -0
  243. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/server/omlx_bridge/__init__.py +0 -0
  244. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/server/omlx_bridge/adapter.py +0 -0
  245. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/server/omlx_bridge/thinking.py +0 -0
  246. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/server_urls.py +0 -0
  247. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/speculative.py +0 -0
  248. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/step3p5_mtp_patch.py +0 -0
  249. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/swival.py +0 -0
  250. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/templates/qwen36_froggeric_v19/chat_template.jinja +0 -0
  251. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/templates/qwen36_froggeric_v21_3/chat_template.jinja +0 -0
  252. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/trace_parity.py +0 -0
  253. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/turboquant.py +0 -0
  254. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/ui/__init__.py +0 -0
  255. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/ui/banner.py +0 -0
  256. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/ui/chat_printer.py +0 -0
  257. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/ui/download_progress.py +0 -0
  258. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/ui/onboarding.py +0 -0
  259. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/ui/panels.py +0 -0
  260. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/ui/progress.py +0 -0
  261. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/verify_kernels.py +0 -0
  262. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/verify_qmv.py +0 -0
  263. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/vision/__init__.py +0 -0
  264. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/vision/processing.py +0 -0
  265. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/vision/qwen3_vl_tower.py +0 -0
  266. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx/vision/splice.py +0 -0
  267. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx.egg-info/dependency_links.txt +0 -0
  268. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx.egg-info/entry_points.txt +0 -0
  269. {mtplx-2.2.0 → mtplx-2.4.0}/mtplx.egg-info/top_level.txt +0 -0
  270. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/agent_user_path_qa.py +0 -0
  271. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/aime_serve_gate.py +0 -0
  272. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/aime_shape_memory_bench.py +0 -0
  273. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/collect_mtp_activation_stats.py +0 -0
  274. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/collect_mtp_hidden_calib.py +0 -0
  275. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/combine_mtp_adapters.py +0 -0
  276. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/compiled_verify_exactness.py +0 -0
  277. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/convert_step37_to_mtplx_step3p5.py +0 -0
  278. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/eval_mtp_corrector.py +0 -0
  279. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/filter_mtp_adapter.py +0 -0
  280. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/fp16_turbo_exactness_20260707.py +0 -0
  281. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/fresh_venv_smoke.sh +0 -0
  282. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/hygiene_scan.sh +0 -0
  283. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/install_macos.sh +0 -0
  284. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/install_preview_global.sh +0 -0
  285. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/kvcache_exactness_audit_20260703.py +0 -0
  286. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/kvcache_soak_20260703.py +0 -0
  287. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/kvcache_warm_probe_20260703.py +0 -0
  288. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/make_fp16_precision_sibling.py +0 -0
  289. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/midform_gate.py +0 -0
  290. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/ocspeed-20260703/abba_final.sh +0 -0
  291. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/ocspeed-20260703/accept_depth_probe.py +0 -0
  292. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/ocspeed-20260703/arm_runner.sh +0 -0
  293. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/ocspeed-20260703/forward_depth_bisect.py +0 -0
  294. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/ocspeed-20260703/longgen_probe.py +0 -0
  295. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/ocspeed-20260703/loop_degradation_probe.py +0 -0
  296. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/ocspeed-20260703/paired_longgen.sh +0 -0
  297. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/ocspeed-20260703/sdpa_microbench.py +0 -0
  298. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/ocspeed-20260703/snapshot_tail.py +0 -0
  299. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/opencode_concurrency_qa.py +0 -0
  300. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/phase0h_paged_verifier_exactness.py +0 -0
  301. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/probe_mlx_pr3026_qsdpa.py +0 -0
  302. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/probe_mx_compile_buckets.py +0 -0
  303. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/probe_paged_gqa_sdpa_routes.py +0 -0
  304. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/prodqa-20260703/candidate_truecold_20260703.py +0 -0
  305. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/prodqa-20260703/cold_pair_recheck.py +0 -0
  306. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/prodqa-20260703/competitors_20260703.sh +0 -0
  307. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/prodqa-20260703/decode_gap_matrix.py +0 -0
  308. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/prodqa-20260703/hermes_pty_driver.py +0 -0
  309. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/prodqa-20260703/omlx_probe.py +0 -0
  310. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/prodqa-20260703/pi_pty_driver.py +0 -0
  311. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/prodqa-20260703/pillar_ab_20260703.py +0 -0
  312. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/prodqa-20260703/tool_gauntlet_20260703.sh +0 -0
  313. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/quality_fp16_parent_logitdiff_20260707.py +0 -0
  314. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/r1_chisquare_verifier_correctness.py +0 -0
  315. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/release_macos_v1.sh +0 -0
  316. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/run_context_degradation_diagnostics.py +0 -0
  317. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/serve_openai_mtplx.py +0 -0
  318. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/session_cache_followup_qa.py +0 -0
  319. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/sparkle_rehearsal_kit.sh +0 -0
  320. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/step_acceptance.py +0 -0
  321. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/step_smoke.py +0 -0
  322. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/train_mtp_adapter_c4.py +0 -0
  323. {mtplx-2.2.0 → mtplx-2.4.0}/scripts/validate_step_mtp_injector.py +0 -0
  324. {mtplx-2.2.0 → mtplx-2.4.0}/setup.cfg +0 -0
  325. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_adaptive.py +0 -0
  326. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_aime_serve_gate.py +0 -0
  327. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_ar_batch_penalties.py +0 -0
  328. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_attention_split.py +0 -0
  329. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_background_warmup.py +0 -0
  330. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_batching_foundation.py +0 -0
  331. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_cache_bank.py +0 -0
  332. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_cli_parity_tools.py +0 -0
  333. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_cold_tier_write_budget.py +0 -0
  334. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_compressed_tensors.py +0 -0
  335. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_config.py +0 -0
  336. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_config_profile_precedence.py +0 -0
  337. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_context_degradation_profiles.py +0 -0
  338. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_correctors.py +0 -0
  339. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_daemon_client.py +0 -0
  340. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_default_models.py +0 -0
  341. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_device_draft_core.py +0 -0
  342. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_diagnostics.py +0 -0
  343. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_download_progress.py +0 -0
  344. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_draft_lm_head.py +0 -0
  345. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_engine_session_concurrency.py +0 -0
  346. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_engine_session_env.py +0 -0
  347. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_fast_sampling.py +0 -0
  348. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_forge_cli.py +0 -0
  349. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_gdn_boundary_retention.py +0 -0
  350. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_generation_store_on_prefill.py +0 -0
  351. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_hygiene_scan.py +0 -0
  352. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_idle_postcommit_subagent.py +0 -0
  353. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_lazy_snapshot_cow.py +0 -0
  354. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_loop_guard.py +0 -0
  355. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_max_idle_watchdog.py +0 -0
  356. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_max_lifecycle.py +0 -0
  357. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_memory_pressure_guard.py +0 -0
  358. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_midform_gate.py +0 -0
  359. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_mtp_activation_stats.py +0 -0
  360. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_mtp_adapters.py +0 -0
  361. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_mtp_alias_load_path.py +0 -0
  362. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_mtp_depth_sweep.py +0 -0
  363. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_nax_verify.py +0 -0
  364. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_onboarding.py +0 -0
  365. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_opencode.py +0 -0
  366. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_orphan_tool_markup.py +0 -0
  367. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_penalties.py +0 -0
  368. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_penalty_request_wiring.py +0 -0
  369. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_persistent_replay.py +0 -0
  370. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_phase0h_paged_verifier_exactness.py +0 -0
  371. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_policy_fingerprint_stability.py +0 -0
  372. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_postcommit_resolve_for_request.py +0 -0
  373. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_postcommit_tools_plumbing.py +0 -0
  374. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_postcommit_wait.py +0 -0
  375. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_prefill_bench.py +0 -0
  376. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_prefill_chunk_defaults.py +0 -0
  377. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_prefill_tps_regression.py +0 -0
  378. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_profiles.py +0 -0
  379. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_prompt_encoding.py +0 -0
  380. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_qwen3_5_mtp_backend.py +0 -0
  381. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_sampling.py +0 -0
  382. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_scoped_reasoning_history.py +0 -0
  383. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_sdpa_gqa_packed.py +0 -0
  384. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_session_bank_env_caps.py +0 -0
  385. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_ssd_boundary_repersist.py +0 -0
  386. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_step3p5_mtp_patch.py +0 -0
  387. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_sustained_long_context_qa.py +0 -0
  388. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_trace_parity.py +0 -0
  389. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_turboquant.py +0 -0
  390. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_turboquant_fallback.py +0 -0
  391. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_ui_progress.py +0 -0
  392. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_validators.py +0 -0
  393. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_vision_session_cache.py +0 -0
  394. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_vision_tower.py +0 -0
  395. {mtplx-2.2.0 → mtplx-2.4.0}/tests/test_vllm_reference.py +0 -0
  396. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/__init__.py +0 -0
  397. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/README.md +0 -0
  398. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/__init__.py +0 -0
  399. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/build.py +0 -0
  400. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/constants.py +0 -0
  401. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v1/copy_blocks.metal +0 -0
  402. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v1/float8.metal +0 -0
  403. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v1/gather_kv_cache.metal +0 -0
  404. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v1/kv_scale_update.metal +0 -0
  405. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v1/pagedattention.metal +0 -0
  406. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v1/reshape_and_cache.metal +0 -0
  407. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v1/utils.metal +0 -0
  408. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v2/copy_blocks.metal +0 -0
  409. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v2/float8.metal +0 -0
  410. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v2/gather_kv_cache.metal +0 -0
  411. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v2/gdn_linear_attention.metal +0 -0
  412. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v2/kv_scale_update.metal +0 -0
  413. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v2/pagedattention.metal +0 -0
  414. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v2/reshape_and_cache.metal +0 -0
  415. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v2/turboquant.metal +0 -0
  416. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/kernels_v2/utils.metal +0 -0
  417. {mtplx-2.2.0 → mtplx-2.4.0}/vllm_metal/metal/paged_ops.cpp +0 -0
@@ -4,6 +4,195 @@ All notable user-facing changes to MTPLX. The format is based on
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
5
5
  [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [2.4.0] - 2026-07-31
8
+
9
+ The 35B speed release: the 35B-A3B MoE gets a compiled decode stack and
10
+ continuous batched serving, the 2.3.0 fan regression is root-caused and
11
+ fixed, tool calling gets another round of contract hardening, and
12
+ structured output can no longer be eaten by an unbounded reasoning
13
+ prelude. Four community contributors landed code in this release.
14
+
15
+ ### Added
16
+
17
+ - 35B-A3B compiled decode stack: target-prefix compiled route, whole-MoE
18
+ fusion, GDN post-conv fusion, and a row-owned router (David Tai, #174).
19
+ - Continuous batched serving for the A3B lane: fixed-shape cohorts,
20
+ ragged KV, fold-in repair, and AR row-packing (David Tai, #200).
21
+ - Laguna S-2.1 support (exact-pin oQ4e, AR-only) with an app catalog
22
+ entry, plus a Poolside `arg_key`/`arg_value` tool-call dialect parser
23
+ (David Tai, #195).
24
+ - Hy3 295B full-residency lane and generic MTP draft-contract hardening
25
+ whose loud recurrent-cache failure also caught a real bug on the Qwen
26
+ lane (David Tai, #208).
27
+ - `/health` now reports smart-fan restore state (`restore_verified`,
28
+ `restore_failures`, `stale_leases_reconciled`) so stuck-fan reports
29
+ are diagnosable from the field (#201).
30
+
31
+ ### Fixed
32
+
33
+ - Fans no longer stay pinned at max after a request ends (#201). A
34
+ failed fan restore was logged once and then treated as restored, so
35
+ the hardware stayed ramped while the server believed it was clean;
36
+ restores now verify the fan rows are back on the Apple auto curve and
37
+ retry with backoff until they are. The ThermalForge daemon-socket
38
+ restore path no longer trusts the daemon's "ok" reply without
39
+ verifying, and falls back to the CLI in the same call. A stale-lease
40
+ watchdog drops any fan lease held while the engine has been
41
+ continuously idle (default 120s, `MTPLX_SMART_FAN_STALE_LEASE_S`).
42
+ - A generation cut by `max_tokens` mid-tool-call now reports
43
+ `finish_reason: "length"` instead of `"tool_calls"`, so agent clients
44
+ continue the turn instead of executing a truncated call (#196, #197
45
+ layers one and two).
46
+ - The think-splitter no longer leaks reasoning into visible content when
47
+ the text contains bare `function=` or `parameter=` strings (#196/#197
48
+ companion fix).
49
+ - Streaming tool-call parsing handles bracket-style dialects with a
50
+ balanced string/escape-aware scanner, buffers incomplete calls instead
51
+ of double-delivering them, and passes through calls to undeclared
52
+ tools per the OpenAI contract instead of dropping them (David Tai,
53
+ #195).
54
+ - Constrained generation bounds the `<think>` prelude at 4000 characters
55
+ (`MTPLX_THINK_PRELUDE_MAX_CHARS`, 0 restores unbounded), so an
56
+ unclosed think block can no longer consume the entire token budget and
57
+ return no document (Jozef Kristek, #213).
58
+ - Forge model probes recover from slow Hugging Face config responses:
59
+ 30s timeout, pinned-SHA retry, positive-MTP-only indexed acceptance,
60
+ and revision-string validation (Philip John Basile, #210).
61
+
62
+ ### Changed
63
+
64
+ - Dependency bumps: pillow 12.3.0, actions/checkout 7.0.1,
65
+ actions/setup-python 7.0.0, pypa/gh-action-pypi-publish 1.14.1.
66
+
67
+ ## [2.3.0] - 2026-07-21
68
+
69
+ The agent reliability release: the #170 tool-argument collapse is
70
+ root-caused and fixed, structured output ships with full speculative
71
+ speed (community-contributed), agent sessions keep their warm cache
72
+ through client history rewrites, and eight findings from an independent
73
+ source review of v2.2.0 are fixed, each with a regression test that
74
+ fails on the pre-fix code.
75
+
76
+ ### Fixed
77
+
78
+ - Agent tool calls with nested arguments no longer collapse to empty `{}`
79
+ arguments (#170). The streaming Qwen-XML tool parser silently discarded
80
+ function-body text that was not wrapped in `<parameter=>` blocks, so a
81
+ model that wrote its arguments as a JSON object inside the
82
+ `<function=...>` envelope — the common slip on nested `edits` arrays —
83
+ produced a schema-valid call with empty arguments on requiredless tools
84
+ and a silently vanished call otherwise. Both the streaming and the final
85
+ parser now accept a pure JSON-object function body as the arguments
86
+ payload, and every unwrapped, lead, or trailing text lane is a loud
87
+ protocol fallback with identical contracts in the two parsers.
88
+ - The injected tool contract no longer shows degenerate `[]` examples for
89
+ array parameters: exemplars are populated from the item schema's own
90
+ keys (an `edits` array renders as
91
+ `[{"search": "ARGUMENT_VALUE", "replace": "ARGUMENT_VALUE"}]`), removing
92
+ an in-prompt template for empty-array emissions.
93
+ - The final tool-call extraction lane (non-stream parsing and the stream
94
+ fallback) no longer fabricates `{}`-argument calls out of function bodies
95
+ it could not read — live-reproduced on v2.2.0 as a `grep` call arriving
96
+ with empty arguments. All extraction dialects now share the strict
97
+ parsers' contract: a pure JSON-object function body is the arguments
98
+ payload, an unreadable body stays visible content, blank-body no-argument
99
+ calls still parse, and partial arguments are delivered exactly as the
100
+ model wrote them (schema validation remains the client's job, per the
101
+ OpenAI protocol).
102
+ - Context-copy speculative rounds now stop accepting at the first
103
+ accepted stop token, exactly like the MTP acceptance loop. Previously
104
+ the copy lane could accept an entire block past a stop, leaving the
105
+ target cache, logits/hidden selection, and MTP history advanced beyond
106
+ the emitted response while the final state was still marked safe to
107
+ commit — a session-cache poisoning risk on recurrent (GDN) models.
108
+ - Context-copy is prompt-only again at the boundary: proposal blocks are
109
+ sliced from the prompt and capped at its edge instead of running into
110
+ the model's own generated output (the self-repetition case the feature
111
+ contract excludes). Boundary-less candidates are skipped inside the
112
+ n-gram index so the best *valid* match still fires.
113
+ - Non-divisor packed MTP quantization widths (5-bit, 3-bit, 6-bit) now
114
+ infer the correct group size via total-bit arithmetic (#182; fix by
115
+ @Jonathangadeaharder in #183). A 5-bit group-64 head previously
116
+ inferred group 60, overwrote the artifact's correct declared contract,
117
+ and made the model unloadable.
118
+ - Long-running daemons no longer accumulate unbounded telemetry: the
119
+ SessionBank eviction log is a bounded ring, the scheduler's
120
+ started-by-batch-key counter collapses per-session key suffixes to
121
+ stable classes, the dashboard per-session TPS map is LRU-bounded, and
122
+ the OpenCode title fast path trims request metrics like every other
123
+ lane (#145-adjacent slow-creep hygiene).
124
+ - The desktop Hugging Face probe now recognizes rootless assistant-pair
125
+ bundles (`mtplx_pair.json` + `target/config.json`) the same way the
126
+ Python runtime does, so the official Gemma4 pair repos classify as
127
+ ready to download instead of unreadable (#107); Forge routes them to
128
+ install-instead-of-rebuild.
129
+ - `mtplx doctor --json` stdout is now guaranteed machine-parseable: the
130
+ report is built with stdout routed to stderr, so third-party lazy
131
+ importers that print() their errors (huggingface_hub does, whenever its
132
+ HTTP dependencies are broken or split across install locations) can no
133
+ longer prefix the JSON document with prose and break `--json` consumers.
134
+ - Agent tool-loop sessions no longer lose their warm cache when the
135
+ client rewrites history (transcript compaction, retroactive tool-result
136
+ digests): a common-prefix identity fallback (≥4096 shared tokens and
137
+ ≥25% of the prompt) keeps the session id instead of minting an
138
+ anonymous one, ending the cold full-context re-prefills those
139
+ rotations caused mid-session.
140
+ - Fan restore goes through the ThermalForge daemon socket instead of the
141
+ app-killing CLI path, and `mtplx pull` detects interrupted downloads
142
+ as incomplete instead of treating them as ready (thanks @titan550,
143
+ #178/#179/#180/#181).
144
+
145
+ ### Changed
146
+
147
+ - `parallel_tool_calls` is now honored: a request that declares it gets
148
+ the declared behavior in both directions (false → at most one tool
149
+ call per turn), with the previous client-profile heuristic kept only
150
+ as the fallback when the field is absent (thanks @PhilipJohnBasile,
151
+ #190 — Android Studio declares false today and was being ignored).
152
+ - Agent tool contract v13: instructs whole-file reads (the old
153
+ "smallest read range" clause provoked storms of 1-to-5-line
154
+ micro-reads) and forbids echoing file contents into visible text
155
+ (double-emitted file bodies inflated agent turns by tens of
156
+ thousands of characters). Measured on live agent sessions: thinking
157
+ share of generated tokens 75% → 6-29%, double emissions eliminated.
158
+
159
+ ### Added
160
+
161
+ - Structured output: `response_format` `json_object` and `json_schema`
162
+ are now enforced with llguidance token masks instead of silently
163
+ ignored — and the grammar composes with the MTP verify loop, so
164
+ constrained requests keep full speculative speed (measured: decode
165
+ parity within noise, under 5ms total mask cost per request). On
166
+ thinking templates a prelude grammar lets reasoning finish before the
167
+ document is forced. Opt-in strict tool-call grammars
168
+ (`MTPLX_TOOL_CALL_STRICT=1`) force every tool call to a declared tool
169
+ name with schema-valid arguments — a real OpenCode session built a
170
+ complete project through the strict lane with zero malformed calls.
171
+ Thanks @PhilipJohnBasile (#186, #187, #188). Requires the `[server]`
172
+ extra, which the desktop app installs by default; bare pip installs
173
+ get a clear 400 with an install hint.
174
+ - Durable per-request telemetry: `--request-log-jsonl` (env
175
+ `MTPLX_REQUEST_LOG_JSONL`) appends every request record as one JSON
176
+ line, and `scripts/session_forensics.py` correlates that log with an
177
+ OpenCode database into a single timeline with detectors for re-prefill
178
+ rewinds, TTFT stalls, thinking marathons, double emissions,
179
+ session-identity rotations, and usage mismatches.
180
+ - An **opt-in** agent-lane reasoning budget (`--agent-thinking-budget`,
181
+ env `MTPLX_THINKING_BUDGET`; OFF by default): at the budget the
182
+ reasoning segment is force-closed with a visible bridge so the turn
183
+ proceeds to its answer or tool call, and every engagement is surfaced
184
+ per-request in telemetry (`thinking_guard`). Below the budget decoding
185
+ is bit-exact; plain chat is never touched.
186
+ - Stream stall watchdog (#86 containment): if a stream receives nothing
187
+ while the model owner's progress heartbeat is frozen for
188
+ `MTPLX_STREAM_STALL_DEADLINE_S` (default 300s, 0 disables), the
189
+ request fails with a structured, diagnosable error and releases its
190
+ slot instead of hanging forever. Healthy long prefills and model loads
191
+ tick the heartbeat and are never affected; the daemon is never killed.
192
+ - `pip install mtplx` now includes Pillow, matching the advertised image
193
+ support in the app and server (#103); previously vision failed at
194
+ import unless the `[server]` extra was installed.
195
+
7
196
  ## [2.2.0] - 2026-07-19
8
197
 
9
198
  The copy-drafting and small-Mac release. Decoding: context-copy
@@ -20,3 +20,7 @@ not include or depend on the vLLM serving stack.
20
20
  This product includes Metal kernel code adapted from dflash-mlx
21
21
  (https://github.com/bstnxbt/dflash-mlx), Copyright dflash-mlx contributors,
22
22
  licensed under the Apache License 2.0. See mtplx/nax_verify.py for details.
23
+
24
+ This product includes the Apache-2.0 licensed MLX implementation for
25
+ Laguna-S-2.1 from PipeNetwork, Copyright 2026 PipeNetwork, under
26
+ mtplx/models/laguna.py.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mtplx
3
- Version: 2.2.0
3
+ Version: 2.4.0
4
4
  Summary: Native MTP speculative decoding for Qwen3-Next on Apple Silicon.
5
5
  Author-email: Youssof Altoukhi <business@youssofal.com>
6
6
  License-Expression: Apache-2.0
@@ -25,6 +25,7 @@ License-File: LICENSE
25
25
  License-File: NOTICE
26
26
  Requires-Dist: fastapi>=0.136
27
27
  Requires-Dist: huggingface-hub>=0.36
28
+ Requires-Dist: pillow>=10
28
29
  Requires-Dist: mlx<0.33,>=0.31; sys_platform == "darwin" and platform_machine == "arm64"
29
30
  Requires-Dist: mlx-lm<0.32,>=0.31; sys_platform == "darwin" and platform_machine == "arm64"
30
31
  Requires-Dist: transformers!=5.13.0,<5.14; sys_platform == "darwin" and platform_machine == "arm64"
@@ -38,7 +39,7 @@ Provides-Extra: competitors
38
39
  Requires-Dist: dflash-mlx==0.1.0; extra == "competitors"
39
40
  Provides-Extra: server
40
41
  Requires-Dist: fastapi>=0.136; extra == "server"
41
- Requires-Dist: pillow>=10; extra == "server"
42
+ Requires-Dist: llguidance>=1.7; extra == "server"
42
43
  Requires-Dist: uvicorn>=0.46; extra == "server"
43
44
  Provides-Extra: dev
44
45
  Requires-Dist: build>=1.2; extra == "dev"
@@ -153,7 +154,26 @@ Fan-backed modes restore your fans to automatic if MTPLX dies for any reason, in
153
154
 
154
155
  ## Compatibility, honestly
155
156
 
156
- `mtplx inspect` classifies any model into four tiers before anything runs: verified, architecture-compatible but unverified, incompatible architecture, or no MTP heads at all. Unverified models refuse to run unless you explicitly force them. There are no silent fallbacks: if MTPLX cannot run a model correctly, it tells you instead of running it badly.
157
+ `mtplx inspect` classifies models before anything runs: verified, architecture-compatible but unverified, AR-only, incompatible architecture, or no MTP heads at all. Unverified models refuse to run unless you explicitly force them. There are no silent fallbacks: if MTPLX cannot run a model correctly, it tells you instead of running it badly.
158
+
159
+ [Laguna-S-2.1 oQ4e](https://huggingface.co/mlx-community/Laguna-S-2.1-oQ4e) is supported through its exact MLX architecture in target-only AR mode:
160
+
161
+ ```bash
162
+ mtplx start cli \
163
+ --model mlx-community/Laguna-S-2.1-oQ4e \
164
+ --download \
165
+ --no-mtp
166
+ ```
167
+
168
+ MTPLX pins that model to revision
169
+ `8e3f5cad513746264940c1c4195de48d7ea345a5` and verifies the 13-shard layout,
170
+ tokenizer, generation config, special tokens map, and Poolside chat template
171
+ before admitting it. The checkpoint has no native MTP head, so an MTP launch is
172
+ rejected before weights load instead of falling back during execution. The
173
+ weights occupy 59.72 GiB (64.13 GB); use a Mac with at least 96 GiB unified
174
+ memory (128 GiB is recommended). MTPLX defaults Laguna to a 32,768-token context
175
+ and response cap, and checks larger explicit server contexts against the active
176
+ Metal memory cap.
157
177
 
158
178
  ## What MTPLX is not
159
179
 
@@ -104,7 +104,26 @@ Fan-backed modes restore your fans to automatic if MTPLX dies for any reason, in
104
104
 
105
105
  ## Compatibility, honestly
106
106
 
107
- `mtplx inspect` classifies any model into four tiers before anything runs: verified, architecture-compatible but unverified, incompatible architecture, or no MTP heads at all. Unverified models refuse to run unless you explicitly force them. There are no silent fallbacks: if MTPLX cannot run a model correctly, it tells you instead of running it badly.
107
+ `mtplx inspect` classifies models before anything runs: verified, architecture-compatible but unverified, AR-only, incompatible architecture, or no MTP heads at all. Unverified models refuse to run unless you explicitly force them. There are no silent fallbacks: if MTPLX cannot run a model correctly, it tells you instead of running it badly.
108
+
109
+ [Laguna-S-2.1 oQ4e](https://huggingface.co/mlx-community/Laguna-S-2.1-oQ4e) is supported through its exact MLX architecture in target-only AR mode:
110
+
111
+ ```bash
112
+ mtplx start cli \
113
+ --model mlx-community/Laguna-S-2.1-oQ4e \
114
+ --download \
115
+ --no-mtp
116
+ ```
117
+
118
+ MTPLX pins that model to revision
119
+ `8e3f5cad513746264940c1c4195de48d7ea345a5` and verifies the 13-shard layout,
120
+ tokenizer, generation config, special tokens map, and Poolside chat template
121
+ before admitting it. The checkpoint has no native MTP head, so an MTP launch is
122
+ rejected before weights load instead of falling back during execution. The
123
+ weights occupy 59.72 GiB (64.13 GB); use a Mac with at least 96 GiB unified
124
+ memory (128 GiB is recommended). MTPLX defaults Laguna to a 32,768-token context
125
+ and response cap, and checks larger explicit server contexts against the active
126
+ Metal memory cap.
108
127
 
109
128
  ## What MTPLX is not
110
129