mtplx 2.2.0__tar.gz → 2.3.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.
- {mtplx-2.2.0 → mtplx-2.3.0}/CHANGELOG.md +129 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/PKG-INFO +3 -2
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/artifacts.py +0 -1
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/commands/public.py +22 -5
- mtplx-2.3.0/mtplx/constrained.py +499 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/context_copy.py +7 -2
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/engine_session.py +68 -1
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/generation.py +306 -31
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/hf_loader.py +35 -2
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/model_scheduler.py +17 -2
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/mtp_patch.py +9 -2
- mtplx-2.3.0/mtplx/progress_heartbeat.py +23 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/server/dashboard_state.py +10 -2
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/server/omlx_bridge/tool_calling.py +77 -1
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/server/openai.py +589 -29
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/session_bank.py +6 -2
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/thermal.py +86 -22
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/thermal_sidecar.py +12 -5
- mtplx-2.3.0/mtplx/thinking_guard.py +442 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/version.py +2 -2
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx.egg-info/PKG-INFO +3 -2
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx.egg-info/SOURCES.txt +9 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx.egg-info/requires.txt +2 -1
- {mtplx-2.2.0 → mtplx-2.3.0}/pyproject.toml +6 -2
- mtplx-2.3.0/scripts/session_forensics.py +439 -0
- mtplx-2.3.0/scripts/walltime-lab/run_project.py +227 -0
- mtplx-2.3.0/tests/test_constrained.py +646 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_context_copy_stats.py +107 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_dashboard_endpoints.py +15 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_hf_loader.py +34 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_model_scheduler.py +25 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_mtp_patch.py +72 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_no_mlx_imports.py +78 -19
- mtplx-2.3.0/tests/test_omlx_bridge.py +292 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_openai_bridge.py +6 -4
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_postcommit_wait_integration.py +58 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_server_openai.py +289 -7
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_session_bank.py +22 -0
- mtplx-2.3.0/tests/test_stream_stall_watchdog.py +66 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_thermal.py +61 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_thermal_sidecar.py +25 -0
- mtplx-2.3.0/tests/test_thinking_guard.py +275 -0
- mtplx-2.3.0/tests/test_tool_nested_args_streaming.py +363 -0
- mtplx-2.2.0/tests/test_omlx_bridge.py +0 -139
- {mtplx-2.2.0 → mtplx-2.3.0}/CITATION.cff +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/LICENSE +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/MANIFEST.in +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/NOTICE +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/README.md +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/adaptive.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/app_settings.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/attention_context.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/attention_split.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/backends/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/backends/deepseek_mtp.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/backends/descriptors.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/backends/gemma4_assistant.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/backends/glm_mtp.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/backends/hy_v3_mtp.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/backends/mimo_mtp.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/backends/nemotron_h_mtp.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/backends/qwen3_next.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/backends/registry.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/backends/step3p5_mtp.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/batching/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/batching/admission.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/batching/buckets.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/batching/scheduler.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/batching/state.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/prompts/aime_2026.jsonl +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/prompts/calibration_coding.jsonl +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/prompts/default.jsonl +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/prompts/flappy.jsonl +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/prompts/long_code.jsonl +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/prompts/long_code_uncapped.jsonl +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/prompts/python_modules_long.jsonl +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/aime.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/batch_equivalence.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/capture_commit_equivalence.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/competitor_baselines.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/contract_probe.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/harness.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/mtp1_gate.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/mtp1_sampler_smoke.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/mtp_adaptive.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/mtp_chain_probe.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/mtp_depth_grid.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/mtp_depth_sweep.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/mtp_tree_probe.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/multi_qmv_probe.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/preflight.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/runtime_smoke.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/session_bank.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/truth.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/verify_profile.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/verify_qmm_probe.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/runners/verify_ratio.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/schema.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/validators/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/validators/aime.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/benchmarks/validators/basic.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/block_attention.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/cache_bank/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/cache_bank/codec.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/cache_bank/cold_tier.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/cache_state.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/chat_encoding.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/cli.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/commands/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/commands/forge.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/compressed_tensors.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/config.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/constants.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/correctors/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/correctors/diagonal_affine.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/correctors/low_rank.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/daemon_client.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/dashboard/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/dashboard/_static/assets/index-BYd4MFty.css +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/dashboard/_static/assets/index-COqTDxL-.js +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/dashboard/_static/index.html +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/deepseek_mtp_patch.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/default_models.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/diagnostics.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/draft_lm_head.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/draft_sampling.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/env.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/errors.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/expert_layout.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/fan_mode.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/fast_sampling.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/gdn_capture.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/gemma4_pair.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/glm_mtp_patch.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/graphbank.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/hardware.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/hy_v3_mtp_patch.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kernel_selfcheck.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kernels/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kernels/copy_leaf.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kernels/fused_norm.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kernels/lm_head_topk.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kernels/logits_topk.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kernels/native_gdn_tail.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kernels/sdpa_2pass.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kernels/sdpa_2pass_paged.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kernels/sdpa_2pass_paged_q8.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kernels/sdpa_gqa_packed.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kernels/verify_mlp_fused.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kpi/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kpi/reference_vllm.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kpi/runtime_kpis.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/kv_quant.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/loop_guard.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/mimo_mtp_patch.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/model_catalog.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/mtp_activation_stats.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/mtp_adapters.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/native_mlp.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/nax_verify.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/nemotron_h_mtp_patch.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/opencode.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/pi.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/prefill_bench.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/profiles.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/proposal_reranker.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/qwen3_5_mtp_patch.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/reasoning_codecs.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/runtime.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/runtime_options.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/sampling.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/server/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/server/omlx_bridge/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/server/omlx_bridge/adapter.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/server/omlx_bridge/thinking.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/server_urls.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/speculative.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/step3p5_mtp_patch.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/swival.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/templates/qwen36_froggeric_v19/chat_template.jinja +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/templates/qwen36_froggeric_v21_3/chat_template.jinja +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/trace_parity.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/turboquant.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/ui/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/ui/banner.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/ui/chat_printer.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/ui/download_progress.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/ui/onboarding.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/ui/panels.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/ui/progress.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/verify_kernels.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/verify_qmv.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/vision/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/vision/processing.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/vision/qwen3_vl_tower.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx/vision/splice.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx.egg-info/dependency_links.txt +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx.egg-info/entry_points.txt +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/mtplx.egg-info/top_level.txt +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/agent_user_path_qa.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/aime_serve_gate.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/aime_shape_memory_bench.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/collect_mtp_activation_stats.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/collect_mtp_hidden_calib.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/combine_mtp_adapters.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/compiled_verify_exactness.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/convert_step37_to_mtplx_step3p5.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/eval_mtp_corrector.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/filter_mtp_adapter.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/fp16_turbo_exactness_20260707.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/fresh_venv_smoke.sh +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/hygiene_scan.sh +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/install_macos.sh +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/install_preview_global.sh +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/kvcache_exactness_audit_20260703.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/kvcache_soak_20260703.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/kvcache_warm_probe_20260703.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/make_fp16_precision_sibling.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/midform_gate.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/ocspeed-20260703/abba_final.sh +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/ocspeed-20260703/accept_depth_probe.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/ocspeed-20260703/arm_runner.sh +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/ocspeed-20260703/forward_depth_bisect.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/ocspeed-20260703/longgen_probe.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/ocspeed-20260703/loop_degradation_probe.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/ocspeed-20260703/paired_longgen.sh +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/ocspeed-20260703/sdpa_microbench.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/ocspeed-20260703/snapshot_tail.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/opencode_concurrency_qa.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/phase0h_paged_verifier_exactness.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/pillar_gate_qa.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/probe_mlx_pr3026_qsdpa.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/probe_mx_compile_buckets.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/probe_paged_gqa_sdpa_routes.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/prodqa-20260703/candidate_truecold_20260703.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/prodqa-20260703/cold_pair_recheck.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/prodqa-20260703/competitors_20260703.sh +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/prodqa-20260703/decode_gap_matrix.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/prodqa-20260703/hermes_pty_driver.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/prodqa-20260703/omlx_probe.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/prodqa-20260703/pi_pty_driver.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/prodqa-20260703/pillar_ab_20260703.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/prodqa-20260703/tool_gauntlet_20260703.sh +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/quality_fp16_parent_logitdiff_20260707.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/r1_chisquare_verifier_correctness.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/release_macos_v1.sh +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/run_context_degradation_diagnostics.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/serve_openai_mtplx.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/session_cache_followup_qa.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/sparkle_rehearsal_kit.sh +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/step_acceptance.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/step_smoke.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/train_mtp_adapter_c4.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/scripts/validate_step_mtp_injector.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/setup.cfg +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_adaptive.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_aime_serve_gate.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_ar_batch_penalties.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_artifacts.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_attention_split.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_background_warmup.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_batching_foundation.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_cache_bank.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_cache_state.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_cli_parity_tools.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_cold_tier_write_budget.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_compressed_tensors.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_config.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_config_profile_precedence.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_context_degradation_profiles.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_correctors.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_daemon_client.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_default_models.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_device_draft_core.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_diagnostics.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_download_progress.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_draft_lm_head.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_engine_session_concurrency.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_engine_session_env.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_fast_sampling.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_forge_cli.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_gdn_boundary_retention.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_generation_store_on_prefill.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_generation_sustained.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_graphbank_compiled_verify.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_hy_v3_mtp_backend.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_hygiene_scan.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_idle_postcommit_subagent.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_kernel_selfcheck.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_lazy_snapshot_cow.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_loop_guard.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_max_idle_watchdog.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_max_lifecycle.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_memory_pressure_guard.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_metal_memory_caps.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_midform_gate.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_model_catalog.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_mtp_activation_stats.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_mtp_adapters.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_mtp_alias_load_path.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_mtp_depth_sweep.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_nax_verify.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_onboarding.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_opencode.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_orphan_tool_markup.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_penalties.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_penalty_request_wiring.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_persistent_replay.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_phase0h_paged_verifier_exactness.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_policy_fingerprint_stability.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_postcommit_prefix_reuse.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_postcommit_resolve_for_request.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_postcommit_tools_plumbing.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_postcommit_wait.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_prefill_bench.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_prefill_chunk_defaults.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_prefill_tps_regression.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_profiles.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_prompt_encoding.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_public_cli.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_qwen3_5_mtp_backend.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_reasoning_stream_split.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_runtime_kpis.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_sampling.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_scoped_reasoning_history.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_sdpa_gqa_packed.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_session_bank_env_caps.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_ssd_boundary_repersist.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_step3p5_mtp_patch.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_sustained_long_context_qa.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_tool_aware_stream_translator.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_trace_parity.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_turboquant.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_turboquant_fallback.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_ui_progress.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_validators.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_vision_session_cache.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_vision_tower.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/tests/test_vllm_reference.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/README.md +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/__init__.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/build.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/constants.py +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v1/copy_blocks.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v1/float8.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v1/gather_kv_cache.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v1/kv_scale_update.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v1/pagedattention.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v1/reshape_and_cache.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v1/utils.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v2/copy_blocks.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v2/float8.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v2/gather_kv_cache.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v2/gdn_linear_attention.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v2/kv_scale_update.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v2/pagedattention.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v2/reshape_and_cache.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v2/turboquant.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/kernels_v2/utils.metal +0 -0
- {mtplx-2.2.0 → mtplx-2.3.0}/vllm_metal/metal/paged_ops.cpp +0 -0
|
@@ -4,6 +4,135 @@ 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.3.0] - 2026-07-21
|
|
8
|
+
|
|
9
|
+
The agent reliability release: the #170 tool-argument collapse is
|
|
10
|
+
root-caused and fixed, structured output ships with full speculative
|
|
11
|
+
speed (community-contributed), agent sessions keep their warm cache
|
|
12
|
+
through client history rewrites, and eight findings from an independent
|
|
13
|
+
source review of v2.2.0 are fixed, each with a regression test that
|
|
14
|
+
fails on the pre-fix code.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Agent tool calls with nested arguments no longer collapse to empty `{}`
|
|
19
|
+
arguments (#170). The streaming Qwen-XML tool parser silently discarded
|
|
20
|
+
function-body text that was not wrapped in `<parameter=>` blocks, so a
|
|
21
|
+
model that wrote its arguments as a JSON object inside the
|
|
22
|
+
`<function=...>` envelope — the common slip on nested `edits` arrays —
|
|
23
|
+
produced a schema-valid call with empty arguments on requiredless tools
|
|
24
|
+
and a silently vanished call otherwise. Both the streaming and the final
|
|
25
|
+
parser now accept a pure JSON-object function body as the arguments
|
|
26
|
+
payload, and every unwrapped, lead, or trailing text lane is a loud
|
|
27
|
+
protocol fallback with identical contracts in the two parsers.
|
|
28
|
+
- The injected tool contract no longer shows degenerate `[]` examples for
|
|
29
|
+
array parameters: exemplars are populated from the item schema's own
|
|
30
|
+
keys (an `edits` array renders as
|
|
31
|
+
`[{"search": "ARGUMENT_VALUE", "replace": "ARGUMENT_VALUE"}]`), removing
|
|
32
|
+
an in-prompt template for empty-array emissions.
|
|
33
|
+
- The final tool-call extraction lane (non-stream parsing and the stream
|
|
34
|
+
fallback) no longer fabricates `{}`-argument calls out of function bodies
|
|
35
|
+
it could not read — live-reproduced on v2.2.0 as a `grep` call arriving
|
|
36
|
+
with empty arguments. All extraction dialects now share the strict
|
|
37
|
+
parsers' contract: a pure JSON-object function body is the arguments
|
|
38
|
+
payload, an unreadable body stays visible content, blank-body no-argument
|
|
39
|
+
calls still parse, and partial arguments are delivered exactly as the
|
|
40
|
+
model wrote them (schema validation remains the client's job, per the
|
|
41
|
+
OpenAI protocol).
|
|
42
|
+
- Context-copy speculative rounds now stop accepting at the first
|
|
43
|
+
accepted stop token, exactly like the MTP acceptance loop. Previously
|
|
44
|
+
the copy lane could accept an entire block past a stop, leaving the
|
|
45
|
+
target cache, logits/hidden selection, and MTP history advanced beyond
|
|
46
|
+
the emitted response while the final state was still marked safe to
|
|
47
|
+
commit — a session-cache poisoning risk on recurrent (GDN) models.
|
|
48
|
+
- Context-copy is prompt-only again at the boundary: proposal blocks are
|
|
49
|
+
sliced from the prompt and capped at its edge instead of running into
|
|
50
|
+
the model's own generated output (the self-repetition case the feature
|
|
51
|
+
contract excludes). Boundary-less candidates are skipped inside the
|
|
52
|
+
n-gram index so the best *valid* match still fires.
|
|
53
|
+
- Non-divisor packed MTP quantization widths (5-bit, 3-bit, 6-bit) now
|
|
54
|
+
infer the correct group size via total-bit arithmetic (#182; fix by
|
|
55
|
+
@Jonathangadeaharder in #183). A 5-bit group-64 head previously
|
|
56
|
+
inferred group 60, overwrote the artifact's correct declared contract,
|
|
57
|
+
and made the model unloadable.
|
|
58
|
+
- Long-running daemons no longer accumulate unbounded telemetry: the
|
|
59
|
+
SessionBank eviction log is a bounded ring, the scheduler's
|
|
60
|
+
started-by-batch-key counter collapses per-session key suffixes to
|
|
61
|
+
stable classes, the dashboard per-session TPS map is LRU-bounded, and
|
|
62
|
+
the OpenCode title fast path trims request metrics like every other
|
|
63
|
+
lane (#145-adjacent slow-creep hygiene).
|
|
64
|
+
- The desktop Hugging Face probe now recognizes rootless assistant-pair
|
|
65
|
+
bundles (`mtplx_pair.json` + `target/config.json`) the same way the
|
|
66
|
+
Python runtime does, so the official Gemma4 pair repos classify as
|
|
67
|
+
ready to download instead of unreadable (#107); Forge routes them to
|
|
68
|
+
install-instead-of-rebuild.
|
|
69
|
+
- `mtplx doctor --json` stdout is now guaranteed machine-parseable: the
|
|
70
|
+
report is built with stdout routed to stderr, so third-party lazy
|
|
71
|
+
importers that print() their errors (huggingface_hub does, whenever its
|
|
72
|
+
HTTP dependencies are broken or split across install locations) can no
|
|
73
|
+
longer prefix the JSON document with prose and break `--json` consumers.
|
|
74
|
+
- Agent tool-loop sessions no longer lose their warm cache when the
|
|
75
|
+
client rewrites history (transcript compaction, retroactive tool-result
|
|
76
|
+
digests): a common-prefix identity fallback (≥4096 shared tokens and
|
|
77
|
+
≥25% of the prompt) keeps the session id instead of minting an
|
|
78
|
+
anonymous one, ending the cold full-context re-prefills those
|
|
79
|
+
rotations caused mid-session.
|
|
80
|
+
- Fan restore goes through the ThermalForge daemon socket instead of the
|
|
81
|
+
app-killing CLI path, and `mtplx pull` detects interrupted downloads
|
|
82
|
+
as incomplete instead of treating them as ready (thanks @titan550,
|
|
83
|
+
#178/#179/#180/#181).
|
|
84
|
+
|
|
85
|
+
### Changed
|
|
86
|
+
|
|
87
|
+
- `parallel_tool_calls` is now honored: a request that declares it gets
|
|
88
|
+
the declared behavior in both directions (false → at most one tool
|
|
89
|
+
call per turn), with the previous client-profile heuristic kept only
|
|
90
|
+
as the fallback when the field is absent (thanks @PhilipJohnBasile,
|
|
91
|
+
#190 — Android Studio declares false today and was being ignored).
|
|
92
|
+
- Agent tool contract v13: instructs whole-file reads (the old
|
|
93
|
+
"smallest read range" clause provoked storms of 1-to-5-line
|
|
94
|
+
micro-reads) and forbids echoing file contents into visible text
|
|
95
|
+
(double-emitted file bodies inflated agent turns by tens of
|
|
96
|
+
thousands of characters). Measured on live agent sessions: thinking
|
|
97
|
+
share of generated tokens 75% → 6-29%, double emissions eliminated.
|
|
98
|
+
|
|
99
|
+
### Added
|
|
100
|
+
|
|
101
|
+
- Structured output: `response_format` `json_object` and `json_schema`
|
|
102
|
+
are now enforced with llguidance token masks instead of silently
|
|
103
|
+
ignored — and the grammar composes with the MTP verify loop, so
|
|
104
|
+
constrained requests keep full speculative speed (measured: decode
|
|
105
|
+
parity within noise, under 5ms total mask cost per request). On
|
|
106
|
+
thinking templates a prelude grammar lets reasoning finish before the
|
|
107
|
+
document is forced. Opt-in strict tool-call grammars
|
|
108
|
+
(`MTPLX_TOOL_CALL_STRICT=1`) force every tool call to a declared tool
|
|
109
|
+
name with schema-valid arguments — a real OpenCode session built a
|
|
110
|
+
complete project through the strict lane with zero malformed calls.
|
|
111
|
+
Thanks @PhilipJohnBasile (#186, #187, #188). Requires the `[server]`
|
|
112
|
+
extra, which the desktop app installs by default; bare pip installs
|
|
113
|
+
get a clear 400 with an install hint.
|
|
114
|
+
- Durable per-request telemetry: `--request-log-jsonl` (env
|
|
115
|
+
`MTPLX_REQUEST_LOG_JSONL`) appends every request record as one JSON
|
|
116
|
+
line, and `scripts/session_forensics.py` correlates that log with an
|
|
117
|
+
OpenCode database into a single timeline with detectors for re-prefill
|
|
118
|
+
rewinds, TTFT stalls, thinking marathons, double emissions,
|
|
119
|
+
session-identity rotations, and usage mismatches.
|
|
120
|
+
- An **opt-in** agent-lane reasoning budget (`--agent-thinking-budget`,
|
|
121
|
+
env `MTPLX_THINKING_BUDGET`; OFF by default): at the budget the
|
|
122
|
+
reasoning segment is force-closed with a visible bridge so the turn
|
|
123
|
+
proceeds to its answer or tool call, and every engagement is surfaced
|
|
124
|
+
per-request in telemetry (`thinking_guard`). Below the budget decoding
|
|
125
|
+
is bit-exact; plain chat is never touched.
|
|
126
|
+
- Stream stall watchdog (#86 containment): if a stream receives nothing
|
|
127
|
+
while the model owner's progress heartbeat is frozen for
|
|
128
|
+
`MTPLX_STREAM_STALL_DEADLINE_S` (default 300s, 0 disables), the
|
|
129
|
+
request fails with a structured, diagnosable error and releases its
|
|
130
|
+
slot instead of hanging forever. Healthy long prefills and model loads
|
|
131
|
+
tick the heartbeat and are never affected; the daemon is never killed.
|
|
132
|
+
- `pip install mtplx` now includes Pillow, matching the advertised image
|
|
133
|
+
support in the app and server (#103); previously vision failed at
|
|
134
|
+
import unless the `[server]` extra was installed.
|
|
135
|
+
|
|
7
136
|
## [2.2.0] - 2026-07-19
|
|
8
137
|
|
|
9
138
|
The copy-drafting and small-Mac release. Decoding: context-copy
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mtplx
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.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:
|
|
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"
|
|
@@ -811,7 +811,6 @@ def _inspect_hf_model(repo_id: str) -> ModelInspection:
|
|
|
811
811
|
config = dict(target_config)
|
|
812
812
|
config["assistant_pair_bundle"] = pair_manifest
|
|
813
813
|
config["mtplx_pair.json"] = True
|
|
814
|
-
config_path = target_path
|
|
815
814
|
config_error = None
|
|
816
815
|
if config is None:
|
|
817
816
|
raise RuntimeError(
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import contextlib
|
|
5
6
|
import hashlib
|
|
6
7
|
import json
|
|
7
8
|
import os
|
|
@@ -1828,6 +1829,22 @@ class _temporary_env:
|
|
|
1828
1829
|
|
|
1829
1830
|
|
|
1830
1831
|
def cmd_doctor(args: Any) -> int:
|
|
1832
|
+
# --json promises machine-parseable stdout. Probes import third-party
|
|
1833
|
+
# packages whose lazy loaders print() import errors straight to stdout
|
|
1834
|
+
# (huggingface_hub does, and a split/partially broken install makes it
|
|
1835
|
+
# certain), which used to prefix the JSON document with prose and break
|
|
1836
|
+
# every consumer. Build the whole report with stdout routed to stderr,
|
|
1837
|
+
# then emit only the document.
|
|
1838
|
+
if getattr(args, "json", False):
|
|
1839
|
+
with contextlib.redirect_stdout(sys.stderr):
|
|
1840
|
+
report = _build_doctor_report(args)
|
|
1841
|
+
_print(report)
|
|
1842
|
+
return 0
|
|
1843
|
+
report = _build_doctor_report(args)
|
|
1844
|
+
return _render_doctor_report(args, report)
|
|
1845
|
+
|
|
1846
|
+
|
|
1847
|
+
def _build_doctor_report(args: Any) -> dict[str, Any]:
|
|
1831
1848
|
env = collect_environment(args.project_root).to_dict()
|
|
1832
1849
|
from mtplx.hf_loader import hf_cache_report
|
|
1833
1850
|
from mtplx.thermal import detect_thermal_control
|
|
@@ -1886,9 +1903,11 @@ def cmd_doctor(args: Any) -> int:
|
|
|
1886
1903
|
output_dir=getattr(args, "output_dir", None),
|
|
1887
1904
|
include_paths=bool(getattr(args, "include_paths", False)),
|
|
1888
1905
|
)
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1906
|
+
return report
|
|
1907
|
+
|
|
1908
|
+
|
|
1909
|
+
def _render_doctor_report(args: Any, report: dict[str, Any]) -> int:
|
|
1910
|
+
if getattr(args, "summary", False):
|
|
1892
1911
|
diagnostics = report["diagnostics"]
|
|
1893
1912
|
print(f"MTPLX doctor: {diagnostics['overall']}")
|
|
1894
1913
|
for check in diagnostics["checks"]:
|
|
@@ -2066,7 +2085,6 @@ def cmd_stop_public(args: Any) -> int:
|
|
|
2066
2085
|
"""Stop a running MTPLX server via its health-reported pid."""
|
|
2067
2086
|
|
|
2068
2087
|
from mtplx.daemon_client import (
|
|
2069
|
-
DAEMON_PROBE_PORTS,
|
|
2070
2088
|
probe_running_daemons,
|
|
2071
2089
|
stop_daemon,
|
|
2072
2090
|
)
|
|
@@ -10420,7 +10438,6 @@ def _quickstart_openwebui_payload(
|
|
|
10420
10438
|
port = int(getattr(args, "port", 8000))
|
|
10421
10439
|
model_id = _public_model_id_for_args(args, str(getattr(args, "model", "")))
|
|
10422
10440
|
base = f"http://{_connect_host_for_bind(host)}:{port}"
|
|
10423
|
-
profile = str(getattr(args, "profile", None) or DEFAULT_PROFILE_NAME)
|
|
10424
10441
|
context_window = _inspection_context_window(inspection)
|
|
10425
10442
|
return {
|
|
10426
10443
|
"integration": "openwebui",
|