decision-toolkit 0.3.0__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/CHANGELOG.md +9 -1
  2. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/PKG-INFO +5 -5
  3. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/README.md +4 -4
  4. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/CATALOG_PROPOSAL.md +14 -12
  5. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/CLI.md +6 -4
  6. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/RELEASE.md +8 -8
  7. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/VARIANTS.md +26 -23
  8. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/models/open-jev-deberta-v3-large.md +1 -1
  9. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/pyproject.toml +1 -1
  10. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/__init__.py +1 -1
  11. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/cli.py +34 -22
  12. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_cli.py +10 -5
  13. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/uv.lock +1 -1
  14. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/.github/workflows/ci.yml +0 -0
  15. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/.github/workflows/docs.yml +0 -0
  16. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/.github/workflows/release.yml +0 -0
  17. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/.gitignore +0 -0
  18. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/CONTRIBUTING.md +0 -0
  19. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/LICENSE +0 -0
  20. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/SECURITY.md +0 -0
  21. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/THIRD_PARTY_NOTICES.md +0 -0
  22. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/bench/README.md +0 -0
  23. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/bench/__init__.py +0 -0
  24. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/bench/load.py +0 -0
  25. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/bench/results/2026-10-20-calibration.json +0 -0
  26. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/bench/results/2026-10-20-load.json +0 -0
  27. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/bench/results/2026-10-20-smoke.json +0 -0
  28. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/bench/run.py +0 -0
  29. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/bench/suites/calibration.jsonl +0 -0
  30. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/bench/suites/smoke.jsonl +0 -0
  31. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/BENCH.md +0 -0
  32. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/CORE.md +0 -0
  33. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/EXAMPLES.md +0 -0
  34. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/OPERATIONS.md +0 -0
  35. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/REST.md +0 -0
  36. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/ROADMAP.md +0 -0
  37. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/index.md +0 -0
  38. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/models/README.md +0 -0
  39. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/models/gliner2.5-decide.md +0 -0
  40. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/models/gliner2.5-multi.md +0 -0
  41. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/models/julia-1.md +0 -0
  42. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/models/laya-multilingual.md +0 -0
  43. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/models/laya.md +0 -0
  44. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/models/opendecider-nano.md +0 -0
  45. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/docs/models/strands-decider-2b.md +0 -0
  46. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/__main__.py +0 -0
  47. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/adapters/__init__.py +0 -0
  48. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/adapters/base.py +0 -0
  49. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/adapters/gliner2.py +0 -0
  50. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/adapters/gliner2_decide.py +0 -0
  51. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/adapters/julia.py +0 -0
  52. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/adapters/laya.py +0 -0
  53. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/adapters/opendecider.py +0 -0
  54. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/adapters/openjev.py +0 -0
  55. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/adapters/strands_decider.py +0 -0
  56. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/calibration.py +0 -0
  57. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/catalog.py +0 -0
  58. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/config.py +0 -0
  59. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/contracts/__init__.py +0 -0
  60. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/contracts/common.py +0 -0
  61. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/contracts/mapping.py +0 -0
  62. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/contracts/openai_decisions_beta.py +0 -0
  63. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/contracts/systemone_v1.py +0 -0
  64. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/decision_model.py +0 -0
  65. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/engine/__init__.py +0 -0
  66. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/errors.py +0 -0
  67. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/limits.py +0 -0
  68. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/metrics.py +0 -0
  69. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/models.py +0 -0
  70. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/observability.py +0 -0
  71. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/py.typed +0 -0
  72. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/registry.py +0 -0
  73. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/results.py +0 -0
  74. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/schema.py +0 -0
  75. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/server.py +0 -0
  76. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/src/decision_toolkit/tracing.py +0 -0
  77. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/__init__.py +0 -0
  78. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/conftest.py +0 -0
  79. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_adapters_gliner2.py +0 -0
  80. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_adapters_gliner2_decide.py +0 -0
  81. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_adapters_julia.py +0 -0
  82. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_adapters_laya.py +0 -0
  83. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_adapters_opendecider.py +0 -0
  84. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_adapters_openjev.py +0 -0
  85. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_adapters_strands.py +0 -0
  86. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_bench.py +0 -0
  87. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_catalog.py +0 -0
  88. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_config.py +0 -0
  89. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_contracts_conformance.py +0 -0
  90. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_core_phase1.py +0 -0
  91. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_decision_model.py +0 -0
  92. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_fuzz_rest.py +0 -0
  93. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_integration_gliner2.py +0 -0
  94. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_models.py +0 -0
  95. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_operations.py +0 -0
  96. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_results.py +0 -0
  97. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_schema.py +0 -0
  98. {decision_toolkit-0.3.0 → decision_toolkit-0.3.1}/tests/test_server.py +0 -0
@@ -1,8 +1,15 @@
1
1
  # Changelog
2
2
 
3
- All notable changes to this project are documented here. Version `0.3.0` is
3
+ All notable changes to this project are documented here. Version `0.3.1` is
4
4
  published on PyPI.
5
5
 
6
+ ## [0.3.1] — 2026-10-21
7
+
8
+ Catalog UX patch: `dtk models list` now prints one row per variant, with
9
+ `variant`, quantization, role, size, cache state and the exact download/select
10
+ commands. `dtk models variants` prints both commands for every variant. No
11
+ model, adapter or REST contract changes.
12
+
6
13
  ## [0.3.0] — 2026-10-21
7
14
 
8
15
  Catalog expansion: three verified ONNX decision models and eight variants.
@@ -185,6 +192,7 @@ README correction. No code or model behavior changed.
185
192
  - Typed `DecisionModel` API with lifecycle, batching, async, usage, warnings,
186
193
  normalized confidence, capabilities, structured events and atomic model store.
187
194
 
195
+ [0.3.1]: https://pypi.org/project/decision-toolkit/0.3.1/
188
196
  [0.3.0]: https://pypi.org/project/decision-toolkit/0.3.0/
189
197
  [0.2.1]: https://pypi.org/project/decision-toolkit/0.2.1/
190
198
  [0.2.0]: https://pypi.org/project/decision-toolkit/0.2.0/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: decision-toolkit
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Local-first toolkit for open-weights decision models: one ONNX engine, one adapter per model contract, typed choice/yes-no/score decisions with probabilities on CPU.
5
5
  Project-URL: Homepage, https://github.com/gia-uh/decision-toolkit
6
6
  Project-URL: Repository, https://github.com/gia-uh/decision-toolkit
@@ -59,7 +59,7 @@ and CLI. `dtk --help` and every subcommand help also include runnable examples.
59
59
  ## Installation
60
60
 
61
61
  ```bash
62
- uv pip install decision-toolkit # library + CLI (0.3.0 on PyPI)
62
+ uv pip install decision-toolkit # library + CLI (0.3.1 on PyPI)
63
63
  uv pip install "decision-toolkit[onnx]" # + onnxruntime, tokenizers (the model runtime)
64
64
  uv pip install "decision-toolkit[server]" # + REST server (FastAPI)
65
65
  ```
@@ -67,7 +67,7 @@ uv pip install "decision-toolkit[server]" # + REST server (FastAPI)
67
67
  The project is managed with [uv](https://docs.astral.sh/uv/) and ships a committed `uv.lock`. Published
68
68
  wheels remain compatible with `pip` for environments that do not use uv.
69
69
 
70
- PyPI: <https://pypi.org/project/decision-toolkit/0.3.0/>. See
70
+ PyPI: <https://pypi.org/project/decision-toolkit/0.3.1/>. See
71
71
  [docs/RELEASE.md](https://github.com/gia-uh/decision-toolkit/blob/main/docs/RELEASE.md)
72
72
  for the Trusted Publishing flow and clean-install checks.
73
73
 
@@ -208,7 +208,7 @@ adapters (there is no generic "any ONNX" adapter).
208
208
  | `julia-1` | `julia` | **m0** — verified: 100/100 argmax parity, 329 ms | `fp32`* (618 MB) |
209
209
  | `opendecider-nano` | `opendecider` | **m0** — official build; prompt ported from pinned code (530 ms) | `q8f16`* (469 MB); `fp16` (792 MB) |
210
210
  | `laya-multilingual` | `laya` | **m0** — fused ONNX; upstream parity (37 ms) | `fp16`* (682 MB); `fp32` (1326 MB) |
211
- | `open-jev-deberta-v3-large` | `open-jev` | **m0** — open Jev repro; 0.854 in-domain (241 ms) | `fp16`* (884 MB); `fp32` (1758 MB); `q4` (487 MB); `q4f16` (357 MB) |
211
+ | `open-jev-deberta-v3-large` | `open-jev` | **m0** — Open-Jev DeBERTa v3 large repro; 0.854 in-domain (241 ms) | `fp16`* (884 MB); `fp32` (1758 MB); `q4` (487 MB); `q4f16` (357 MB) |
212
212
  | `strands-decider-2b` | `strands-decider` | **m0** — reference fixture match (719 ms) | `q4f16`* (1114 MB); `q8` (1821 MB) |
213
213
 
214
214
  **Only `m0` models are in the catalog.** Researched-but-unavailable models
@@ -225,7 +225,7 @@ own repo files, size and role. A `*` in the table above marks the default.
225
225
  `dtk models list` always shows every catalogued variant and what is cached:
226
226
 
227
227
  ```bash
228
- dtk models list # all variants; * = default
228
+ dtk models list # one row per variant; * = default
229
229
  dtk models list --quant # add the quantization labels
230
230
  dtk models variants gliner2.5-multi # full details for one model
231
231
  ```
@@ -21,7 +21,7 @@ and CLI. `dtk --help` and every subcommand help also include runnable examples.
21
21
  ## Installation
22
22
 
23
23
  ```bash
24
- uv pip install decision-toolkit # library + CLI (0.3.0 on PyPI)
24
+ uv pip install decision-toolkit # library + CLI (0.3.1 on PyPI)
25
25
  uv pip install "decision-toolkit[onnx]" # + onnxruntime, tokenizers (the model runtime)
26
26
  uv pip install "decision-toolkit[server]" # + REST server (FastAPI)
27
27
  ```
@@ -29,7 +29,7 @@ uv pip install "decision-toolkit[server]" # + REST server (FastAPI)
29
29
  The project is managed with [uv](https://docs.astral.sh/uv/) and ships a committed `uv.lock`. Published
30
30
  wheels remain compatible with `pip` for environments that do not use uv.
31
31
 
32
- PyPI: <https://pypi.org/project/decision-toolkit/0.3.0/>. See
32
+ PyPI: <https://pypi.org/project/decision-toolkit/0.3.1/>. See
33
33
  [docs/RELEASE.md](https://github.com/gia-uh/decision-toolkit/blob/main/docs/RELEASE.md)
34
34
  for the Trusted Publishing flow and clean-install checks.
35
35
 
@@ -170,7 +170,7 @@ adapters (there is no generic "any ONNX" adapter).
170
170
  | `julia-1` | `julia` | **m0** — verified: 100/100 argmax parity, 329 ms | `fp32`* (618 MB) |
171
171
  | `opendecider-nano` | `opendecider` | **m0** — official build; prompt ported from pinned code (530 ms) | `q8f16`* (469 MB); `fp16` (792 MB) |
172
172
  | `laya-multilingual` | `laya` | **m0** — fused ONNX; upstream parity (37 ms) | `fp16`* (682 MB); `fp32` (1326 MB) |
173
- | `open-jev-deberta-v3-large` | `open-jev` | **m0** — open Jev repro; 0.854 in-domain (241 ms) | `fp16`* (884 MB); `fp32` (1758 MB); `q4` (487 MB); `q4f16` (357 MB) |
173
+ | `open-jev-deberta-v3-large` | `open-jev` | **m0** — Open-Jev DeBERTa v3 large repro; 0.854 in-domain (241 ms) | `fp16`* (884 MB); `fp32` (1758 MB); `q4` (487 MB); `q4f16` (357 MB) |
174
174
  | `strands-decider-2b` | `strands-decider` | **m0** — reference fixture match (719 ms) | `q4f16`* (1114 MB); `q8` (1821 MB) |
175
175
 
176
176
  **Only `m0` models are in the catalog.** Researched-but-unavailable models
@@ -187,7 +187,7 @@ own repo files, size and role. A `*` in the table above marks the default.
187
187
  `dtk models list` always shows every catalogued variant and what is cached:
188
188
 
189
189
  ```bash
190
- dtk models list # all variants; * = default
190
+ dtk models list # one row per variant; * = default
191
191
  dtk models list --quant # add the quantization labels
192
192
  dtk models variants gliner2.5-multi # full details for one model
193
193
  ```
@@ -1,8 +1,9 @@
1
1
  # Catalog proposal: three ONNX decision models
2
2
 
3
3
  **Date:** 2026-10-21
4
- **Status:** implemented and verified in the working tree
5
- **Scope:** add Laya multilingual, Open-Jev DeBERTa v3 large and Strands Decider 2B
4
+ **Status:** published in `0.3.0`
5
+ **Scope:** add Laya multilingual, Open-Jev DeBERTa v3 large and Strands Decider 2B
6
+ **Release:** <https://pypi.org/project/decision-toolkit/0.3.0/>
6
7
 
7
8
  ## Executive summary
8
9
 
@@ -57,14 +58,14 @@ ONNX Runtime 1.31.0, CPU):
57
58
  |---|---|---:|
58
59
  | Laya multilingual | fp16 | 37.4 ms |
59
60
  | Laya multilingual | fp32 | 34.1 ms |
60
- | Open-Jev | fp16 | 241.2 ms |
61
- | Open-Jev | fp32 | 78.2 ms |
62
- | Open-Jev | q4 | 56.0 ms |
63
- | Open-Jev | q4f16 | 219.4 ms |
61
+ | Open-Jev DeBERTa v3 large | fp16 | 241.2 ms |
62
+ | Open-Jev DeBERTa v3 large | fp32 | 78.2 ms |
63
+ | Open-Jev DeBERTa v3 large | q4 | 56.0 ms |
64
+ | Open-Jev DeBERTa v3 large | q4f16 | 219.4 ms |
64
65
  | Strands Decider 2B | q4f16 | 719.3 ms |
65
66
  | Strands Decider 2B | q8 | 1467.2 ms |
66
67
 
67
- The Open-Jev 4-bit paths are size/edge choices; they are not assumed to be
68
+ The Open-Jev DeBERTa v3 large 4-bit paths are size/edge choices; they are not assumed to be
68
69
  faster or more accurate. Strands is a 2B model and is intentionally slower
69
70
  than the other catalog entries.
70
71
 
@@ -72,7 +73,7 @@ than the other catalog entries.
72
73
 
73
74
  - **Laya multilingual:** upstream conversion reports fp32 max |Δp| 1e-4 and
74
75
  fp16 0.035 against PyTorch; local fp16/fp32 agree on the audit answers.
75
- - **Open-Jev:** upstream reports 0.854 in-domain and 0.690 OOD accuracy, plus
76
+ - **Open-Jev DeBERTa v3 large:** upstream reports 0.854 in-domain and 0.690 OOD accuracy, plus
76
77
  0.022 in-domain ECE. Local fp16/fp32 agree on the published example; q4
77
78
  variants are explicitly edge builds.
78
79
  - **Strands Decider 2B:** reference fixture matches within 0.018 max
@@ -84,7 +85,7 @@ independent reproduction of the full upstream training evaluation.
84
85
  ## Quantization policy
85
86
 
86
87
  - Default variants are chosen for a balance of quality, size and CPU latency:
87
- Laya fp16, Open-Jev fp16, Strands q4f16.
88
+ Laya fp16, Open-Jev DeBERTa v3 large fp16, Strands q4f16.
88
89
  - `fp32` remains a quality variant where published.
89
90
  - `q4`/`q4f16`/`q8` are exposed, but their thresholds must be validated on the
90
91
  user's data; no silent fallback exists.
@@ -98,10 +99,11 @@ independent reproduction of the full upstream training evaluation.
98
99
  runtime checks. A larger acceptance run is still desirable.
99
100
  2. **Strands CPU cost.** q8 takes ~1.5 s per simple question; this is suitable
100
101
  for local/agentic workflows, not high-throughput serving.
101
- 3. **Quantization drift.** Open-Jev q4 and Strands q4f16 can move near-ties;
102
+ 3. **Quantization drift.** Open-Jev DeBERTa v3 large q4 and Strands q4f16 can move near-ties;
102
103
  the model cards call this out.
103
- 4. **Coverage.** Laya multilingual is weak on low-resource languages; Open-Jev
104
- is English-only and weak on unseen score scales; Strands is a 2B model with
104
+ 4. **Coverage.** Laya multilingual is weak on low-resource languages;
105
+ Open-Jev DeBERTa v3 large is English-only and weak on unseen score scales;
106
+ Strands is a 2B model with
105
107
  its own upstream limitations.
106
108
  5. **No image/box support.** The catalog remains text-only.
107
109
 
@@ -184,10 +184,12 @@ classification or serve command overrides it for that command. If `--variant`
184
184
  is omitted, the catalog default is used unless `dtk models use` selected another
185
185
  one.
186
186
 
187
- `models list --json` always includes license, quant, adapter, capabilities, all
188
- variants, the default variant, cached variants, `current` and `current_variant`.
189
- The text table always shows variants and cached variants; `--license`, `--quant`
190
- and `--adapter` add their columns.
187
+ `models list` text output has **one row per variant**, with `id`, `variant`,
188
+ `quant`, `role`, `size` and `cached`, followed by the exact download/select
189
+ commands. `--license` and `--adapter` add catalog columns; `--quant` is accepted
190
+ for compatibility because quantization is always shown. `--json` returns the
191
+ nested model tree: one object per model, each with its `variants` and
192
+ `cached_variants`.
191
193
 
192
194
  See [Variants and quantization](VARIANTS.md) for the full table and cache
193
195
  layout.
@@ -10,7 +10,7 @@ and selection in the CLI and documentation; `0.1.7` aligned variant selection
10
10
  across the library, CLI and REST API; `0.2.0` corrected the REST conformance
11
11
  claims and wire shapes to the published TypeSafe and OpenAI schemas; `0.2.1`
12
12
  changed the public documentation URLs to this repository's Pages site; `0.3.0`
13
- added the Laya multilingual, Open-Jev and Strands Decider ONNX models.
13
+ added the Laya multilingual, Open-Jev DeBERTa v3 large and Strands Decider ONNX models; `0.3.1` made the catalog list one row per variant with exact commands.
14
14
 
15
15
  ## Local build and verification
16
16
 
@@ -37,7 +37,7 @@ Clean install test (no `PYTHONPATH`):
37
37
  ```bash
38
38
  uv venv --python 3.12 /tmp/dtk-wheel
39
39
  uv pip install --python /tmp/dtk-wheel/bin/python \
40
- dist/decision_toolkit-0.3.0-py3-none-any.whl
40
+ dist/decision_toolkit-0.3.1-py3-none-any.whl
41
41
  uv pip check --python /tmp/dtk-wheel/bin/python
42
42
  /tmp/dtk-wheel/bin/dtk --version
43
43
  /tmp/dtk-wheel/bin/dtk models list --json
@@ -48,7 +48,7 @@ With inference and server extras:
48
48
 
49
49
  ```bash
50
50
  uv pip install --python /tmp/dtk-wheel/bin/python \
51
- "dist/decision_toolkit-0.3.0-py3-none-any.whl[onnx,server,tracing]"
51
+ "dist/decision_toolkit-0.3.1-py3-none-any.whl[onnx,server,tracing]"
52
52
  /tmp/dtk-wheel/bin/dtk decide --model gliner2.5-decide ...
53
53
  /tmp/dtk-wheel/bin/dtk serve --model gliner2.5-decide --warmup --port 8016
54
54
  curl -s http://127.0.0.1:8016/health
@@ -82,8 +82,8 @@ No long-lived PyPI token is needed; the workflow uses GitHub OIDC
82
82
  4. Create and push an annotated tag:
83
83
 
84
84
  ```bash
85
- git tag -a v0.3.0 -m "decision-toolkit 0.3.0"
86
- git push origin v0.3.0
85
+ git tag -a v0.3.1 -m "decision-toolkit 0.3.1"
86
+ git push origin v0.3.1
87
87
  ```
88
88
 
89
89
  5. `.github/workflows/release.yml` builds once, publishes to **TestPyPI**, then
@@ -132,9 +132,9 @@ to TestPyPI without publishing to PyPI or creating a GitHub release.
132
132
 
133
133
  ## Published release
134
134
 
135
- `0.3.0` is published through Trusted Publishing on 2026-10-21:
135
+ `0.3.1` is published through Trusted Publishing on 2026-10-21:
136
136
 
137
- <https://pypi.org/project/decision-toolkit/0.3.0/>
137
+ <https://pypi.org/project/decision-toolkit/0.3.1/>
138
138
 
139
139
  `0.1.0` was the first release; `0.1.1` refreshed the PyPI description; `0.1.2`
140
140
  validated the OIDC TestPyPI → PyPI flow; `0.1.3` added post-publish install
@@ -144,7 +144,7 @@ published to TestPyPI only; `0.1.5` fixed TestPyPI resolution; `0.1.6` added
144
144
  complete variant/quantization visibility and CLI selection; `0.1.7` aligned
145
145
  selection across library, CLI and REST; `0.2.0` corrected the REST conformance
146
146
  claims and wire shapes; `0.2.1` changed the public documentation URLs; `0.3.0`
147
- added the three new ONNX decision models.
147
+ added the three new ONNX decision models; `0.3.1` made the catalog list one row per variant.
148
148
 
149
149
  The tag-triggered workflow remains the preferred path for future releases once
150
150
  the TestPyPI/PyPI trusted publishers and protected environments are configured.
@@ -18,23 +18,23 @@ have not passed the catalog gates are not exposed as variants.
18
18
  A `*` marks the default variant. It is used when `--variant` is omitted and no
19
19
  other variant was selected with `dtk models use`.
20
20
 
21
- | Model | Variant | Quantization | Size | Role |
22
- | --- | --- | --- | ---: | --- |
23
- | `gliner2.5-multi` | `fp16` * | fp16 encoder + fp32 classifier | 577.1 MB | default |
24
- | `gliner2.5-multi` | `fp32` | fp32 encoder + fp32 classifier | 1131.9 MB | quality |
25
- | `gliner2.5-decide` | `q4f16` * | q4/fp16 | 523.5 MB | default |
26
- | `laya` | `q8` * | int8 | 527.9 MB | default |
27
- | `julia-1` | `fp32` * | fp32 | 618.2 MB | default |
28
- | `opendecider-nano` | `q8f16` * | int8/fp16 | 468.8 MB | default |
29
- | `opendecider-nano` | `fp16` | fp16 | 791.9 MB | quality |
30
- | `laya-multilingual` | `fp16` * | fp16 | 681.8 MB | default |
31
- | `laya-multilingual` | `fp32` | fp32 | 1325.6 MB | quality |
32
- | `open-jev-deberta-v3-large` | `fp16` * | fp16 | 883.5 MB | default |
33
- | `open-jev-deberta-v3-large` | `fp32` | fp32 | 1757.9 MB | quality |
34
- | `open-jev-deberta-v3-large` | `q4` | q4 | 486.7 MB | edge |
35
- | `open-jev-deberta-v3-large` | `q4f16` | q4/fp16 | 357.0 MB | edge |
36
- | `strands-decider-2b` | `q4f16` * | q4/fp16 | 1113.6 MB | default |
37
- | `strands-decider-2b` | `q8` | int8 | 1821.4 MB | quality |
21
+ | Model | Variant | Quantization | Size | Role | Download |
22
+ | --- | --- | --- | ---: | --- | --- |
23
+ | `gliner2.5-multi` | `fp16` * | fp16 encoder + fp32 classifier | 577.1 MB | default | `dtk models download gliner2.5-multi --variant fp16` |
24
+ | `gliner2.5-multi` | `fp32` | fp32 encoder + fp32 classifier | 1131.9 MB | quality | `dtk models download gliner2.5-multi --variant fp32` |
25
+ | `gliner2.5-decide` | `q4f16` * | q4/fp16 | 523.5 MB | default | `dtk models download gliner2.5-decide --variant q4f16` |
26
+ | `laya` | `q8` * | int8 | 527.9 MB | default | `dtk models download laya --variant q8` |
27
+ | `julia-1` | `fp32` * | fp32 | 618.2 MB | default | `dtk models download julia-1 --variant fp32` |
28
+ | `opendecider-nano` | `q8f16` * | int8/fp16 | 468.8 MB | default | `dtk models download opendecider-nano --variant q8f16` |
29
+ | `opendecider-nano` | `fp16` | fp16 | 791.9 MB | quality | `dtk models download opendecider-nano --variant fp16` |
30
+ | `laya-multilingual` | `fp16` * | fp16 | 681.8 MB | default | `dtk models download laya-multilingual --variant fp16` |
31
+ | `laya-multilingual` | `fp32` | fp32 | 1325.6 MB | quality | `dtk models download laya-multilingual --variant fp32` |
32
+ | `open-jev-deberta-v3-large` | `fp16` * | fp16 | 883.5 MB | default | `dtk models download open-jev-deberta-v3-large --variant fp16` |
33
+ | `open-jev-deberta-v3-large` | `fp32` | fp32 | 1757.9 MB | quality | `dtk models download open-jev-deberta-v3-large --variant fp32` |
34
+ | `open-jev-deberta-v3-large` | `q4` | q4 | 486.7 MB | edge | `dtk models download open-jev-deberta-v3-large --variant q4` |
35
+ | `open-jev-deberta-v3-large` | `q4f16` | q4/fp16 | 357.0 MB | edge | `dtk models download open-jev-deberta-v3-large --variant q4f16` |
36
+ | `strands-decider-2b` | `q4f16` * | q4/fp16 | 1113.6 MB | default | `dtk models download strands-decider-2b --variant q4f16` |
37
+ | `strands-decider-2b` | `q8` | int8 | 1821.4 MB | quality | `dtk models download strands-decider-2b --variant q8` |
38
38
 
39
39
  Models with a single row have only one catalogued, verified build. That does
40
40
  not mean other conversions do not exist upstream; it means they have not passed
@@ -87,12 +87,15 @@ dtk models variants opendecider-nano --json
87
87
  Example:
88
88
 
89
89
  ```text
90
- id variants cached
91
- gliner2.5-multi fp16*, fp32 fp16
92
- gliner2.5-decide q4f16* q4f16
93
- opendecider-nano q8f16*, fp16 q8f16
94
-
95
- * default variant. Use `dtk models variants <id>` for details and install commands.
90
+ id variant quant role size cached
91
+ gliner2.5-multi fp16* fp16 default 577.1 MB ✓
92
+ gliner2.5-multi fp32 fp32 quality 1131.9 MB ✓
93
+ gliner2.5-decide q4f16* q4/fp16 default 523.5 MB ✓
94
+ laya q8* int8 default 527.9 MB ✓
95
+
96
+ * default variant.
97
+ download: dtk models download <id> --variant <name>
98
+ select: dtk models use <id> --variant <name>
96
99
  ```
97
100
 
98
101
  ## Download a different quantization
@@ -65,7 +65,7 @@ and re-check thresholds. See [Variants and quantization](../VARIANTS.md).
65
65
  (upstream in-domain 0.85 vs OOD 0.69).
66
66
  - Score on unseen level sets is weak in the upstream evaluation.
67
67
  - It chooses among supplied options; it cannot generate explanations.
68
- - This is an independent open-jev reproduction, not an official TypeSafe model.
68
+ - This is an independent Open-Jev DeBERTa v3 large reproduction, not an official TypeSafe model.
69
69
 
70
70
  ## Usage
71
71
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "decision-toolkit"
7
- version = "0.3.0"
7
+ version = "0.3.1"
8
8
  description = "Local-first toolkit for open-weights decision models: one ONNX engine, one adapter per model contract, typed choice/yes-no/score decisions with probabilities on CPU."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -7,7 +7,7 @@ questions with a calibrated probability for every option, on CPU.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- __version__ = "0.3.0"
10
+ __version__ = "0.3.1"
11
11
 
12
12
  from .adapters import register_adapter
13
13
  from .calibration import brier_score, expected_calibration_error, threshold_sweep
@@ -709,35 +709,43 @@ def _cmd_models(args: argparse.Namespace) -> int:
709
709
  if as_json:
710
710
  _json_out(payloads)
711
711
  return EXIT_OK
712
- headers = ["", "id", "variants"]
712
+ headers = ["", "id", "variant", "quant", "role", "size", "cached"]
713
713
  if args.show_adapter:
714
- headers.append("adapter")
714
+ headers.insert(2, "adapter")
715
715
  if args.show_license:
716
- headers.append("license")
717
- if args.show_quant:
718
- headers.append("quant")
719
- headers.append("cached")
716
+ headers.insert(3, "license")
720
717
  rows = []
721
718
  for model, payload in zip(catalog.CATALOG, payloads):
722
719
  default = model.default_variant
723
- variants = ", ".join(
724
- f"{variant.name}*" if variant is default else variant.name
725
- for variant in model.variants
726
- ) or "—"
727
- row: list[Any] = ["★" if model.id == current else " ", model.id, variants]
728
- if args.show_adapter:
729
- row.append(model.adapter)
730
- if args.show_license:
731
- row.append(model.license)
732
- if args.show_quant:
733
- row.append(
734
- ", ".join(variant.quant for variant in model.variants) or "—"
720
+ cached_variants = set(payload["cached_variants"])
721
+ if not model.variants:
722
+ rows.append(["", model.id, "—", "—", "—", "—", "—"])
723
+ continue
724
+ for variant in model.variants:
725
+ is_current = model.id == current and (
726
+ current_variant == variant.name
727
+ if current_variant is not None
728
+ else variant is default
735
729
  )
736
- cached_label = ", ".join(payload["cached_variants"]) or "—"
737
- row.append(cached_label)
738
- rows.append(row)
730
+ label = f"{variant.name}*" if variant is default else variant.name
731
+ row: list[Any] = [
732
+ "★" if is_current else "",
733
+ model.id,
734
+ label,
735
+ variant.quant,
736
+ variant.role,
737
+ f"{variant.size_mb:.1f} MB",
738
+ "✓" if variant.name in cached_variants else "",
739
+ ]
740
+ if args.show_adapter:
741
+ row.insert(2, model.adapter)
742
+ if args.show_license:
743
+ row.insert(3, model.license)
744
+ rows.append(row)
739
745
  _print_table(headers, rows)
740
- print("\n* default variant. Use `dtk models variants <id>` for details and install commands.")
746
+ print("\n* default variant.")
747
+ print("download: dtk models download <id> --variant <name>")
748
+ print("select: dtk models use <id> --variant <name>")
741
749
  return EXIT_OK
742
750
 
743
751
  if command == "variants":
@@ -777,6 +785,10 @@ def _cmd_models(args: argparse.Namespace) -> int:
777
785
  f" download: dtk models download {model.id} "
778
786
  f"--variant {variant.name}"
779
787
  )
788
+ print(
789
+ f" use: dtk models use {model.id} "
790
+ f"--variant {variant.name}"
791
+ )
780
792
  if not model.variants:
781
793
  print(" (no downloadable ONNX variant yet)")
782
794
  else:
@@ -192,9 +192,12 @@ def test_models_list_shows_all_cached_variants(home, fake_snapshot, capsys):
192
192
  store.download("gliner2.5-multi", variant="fp32")
193
193
  assert cli.main(["--home", str(home), "models", "list"]) == 0
194
194
  output = _out(capsys)
195
- row = next(line for line in output.splitlines() if "gliner2.5-multi" in line)
196
- assert "fp16*, fp32" in row
197
- assert "fp16, fp32" in row
195
+ rows = [line for line in output.splitlines() if "gliner2.5-multi" in line]
196
+ assert len(rows) == 2
197
+ assert any("fp16*" in row and "✓" in row for row in rows)
198
+ assert any("fp32" in row and "✓" in row for row in rows)
199
+ assert "download: dtk models download <id> --variant <name>" in output
200
+ assert "select: dtk models use <id> --variant <name>" in output
198
201
 
199
202
 
200
203
  def test_models_list_json_and_columns(home, capsys):
@@ -226,8 +229,10 @@ def test_models_list_json_and_columns(home, capsys):
226
229
  assert "license" in text
227
230
  assert "quant" in text
228
231
  assert "adapter" in text
229
- assert "fp16*, fp32" in text
230
- assert "fp16, fp32" in text
232
+ assert "fp16*" in text
233
+ assert "fp32" in text
234
+ assert "laya-multilingual" in text
235
+ assert "open-jev-deberta-v3-large" in text
231
236
 
232
237
 
233
238
  def test_models_variants_text_and_json(home, capsys):
@@ -349,7 +349,7 @@ wheels = [
349
349
 
350
350
  [[package]]
351
351
  name = "decision-toolkit"
352
- version = "0.3.0"
352
+ version = "0.3.1"
353
353
  source = { editable = "." }
354
354
  dependencies = [
355
355
  { name = "huggingface-hub" },