decision-toolkit 0.3.1__tar.gz → 0.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.
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/CHANGELOG.md +19 -1
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/PKG-INFO +8 -8
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/README.md +7 -7
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/EXAMPLES.md +3 -3
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/RELEASE.md +11 -8
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/REST.md +19 -19
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/VARIANTS.md +15 -10
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/pyproject.toml +1 -1
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/__init__.py +1 -1
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/catalog.py +18 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/contracts/openai_decisions_beta.py +1 -1
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/contracts/systemone_v1.py +0 -1
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/registry.py +8 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/server.py +69 -16
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_server.py +52 -8
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/uv.lock +1 -1
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/.github/workflows/ci.yml +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/.github/workflows/docs.yml +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/.github/workflows/release.yml +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/.gitignore +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/CONTRIBUTING.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/LICENSE +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/SECURITY.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/THIRD_PARTY_NOTICES.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/bench/README.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/bench/__init__.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/bench/load.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/bench/results/2026-10-20-calibration.json +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/bench/results/2026-10-20-load.json +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/bench/results/2026-10-20-smoke.json +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/bench/run.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/bench/suites/calibration.jsonl +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/bench/suites/smoke.jsonl +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/BENCH.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/CATALOG_PROPOSAL.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/CLI.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/CORE.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/OPERATIONS.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/ROADMAP.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/index.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/models/README.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/models/gliner2.5-decide.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/models/gliner2.5-multi.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/models/julia-1.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/models/laya-multilingual.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/models/laya.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/models/open-jev-deberta-v3-large.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/models/opendecider-nano.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/docs/models/strands-decider-2b.md +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/__main__.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/adapters/__init__.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/adapters/base.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/adapters/gliner2.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/adapters/gliner2_decide.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/adapters/julia.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/adapters/laya.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/adapters/opendecider.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/adapters/openjev.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/adapters/strands_decider.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/calibration.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/cli.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/config.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/contracts/__init__.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/contracts/common.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/contracts/mapping.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/decision_model.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/engine/__init__.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/errors.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/limits.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/metrics.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/models.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/observability.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/py.typed +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/results.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/schema.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/tracing.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/__init__.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/conftest.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_adapters_gliner2.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_adapters_gliner2_decide.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_adapters_julia.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_adapters_laya.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_adapters_opendecider.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_adapters_openjev.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_adapters_strands.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_bench.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_catalog.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_cli.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_config.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_contracts_conformance.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_core_phase1.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_decision_model.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_fuzz_rest.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_integration_gliner2.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_models.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_operations.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_results.py +0 -0
- {decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/tests/test_schema.py +0 -0
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
All notable changes to this project are documented here. Version `0.
|
|
3
|
+
All notable changes to this project are documented here. Version `0.4.0` is
|
|
4
4
|
published on PyPI.
|
|
5
5
|
|
|
6
|
+
## [0.4.0] — 2026-10-21
|
|
7
|
+
|
|
8
|
+
REST variant-selection correction. Quantizations are selected through standard
|
|
9
|
+
model aliases (`id@variant`), not a non-standard `variant` body field. The same
|
|
10
|
+
REST process can load two variants of one base model in separate registry slots.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Removed `variant` from System One and OpenAI request bodies; standard clients
|
|
15
|
+
now see only the public request fields.
|
|
16
|
+
- Added `catalog-id@variant` model aliases to `/v1/models` and
|
|
17
|
+
`/v1/models/{id}`. The standard `model` field selects the alias.
|
|
18
|
+
- Registry keys and slots are per alias, so `laya-multilingual@fp16` and
|
|
19
|
+
`laya-multilingual@fp32` load independently and concurrently.
|
|
20
|
+
- Updated README, REST, variants, examples and CLI help so REST never shows a
|
|
21
|
+
variant field in a standard request body.
|
|
22
|
+
|
|
6
23
|
## [0.3.1] — 2026-10-21
|
|
7
24
|
|
|
8
25
|
Catalog UX patch: `dtk models list` now prints one row per variant, with
|
|
@@ -192,6 +209,7 @@ README correction. No code or model behavior changed.
|
|
|
192
209
|
- Typed `DecisionModel` API with lifecycle, batching, async, usage, warnings,
|
|
193
210
|
normalized confidence, capabilities, structured events and atomic model store.
|
|
194
211
|
|
|
212
|
+
[0.4.0]: https://pypi.org/project/decision-toolkit/0.4.0/
|
|
195
213
|
[0.3.1]: https://pypi.org/project/decision-toolkit/0.3.1/
|
|
196
214
|
[0.3.0]: https://pypi.org/project/decision-toolkit/0.3.0/
|
|
197
215
|
[0.2.1]: https://pypi.org/project/decision-toolkit/0.2.1/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: decision-toolkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
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.
|
|
62
|
+
uv pip install decision-toolkit # library + CLI (0.4.0 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.
|
|
70
|
+
PyPI: <https://pypi.org/project/decision-toolkit/0.4.0/>. 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
|
|
|
@@ -248,11 +248,11 @@ dtk models current --json # {"current": "...", "variant": "fp32"}
|
|
|
248
248
|
dtk decide --model gliner2.5-multi --variant fp16 --state "..." --q 'cat=choice:a|b'
|
|
249
249
|
```
|
|
250
250
|
|
|
251
|
-
From Python: `DecisionModel("gliner2.5-multi", variant="fp32")`. REST
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
variant
|
|
255
|
-
|
|
251
|
+
From Python: `DecisionModel("gliner2.5-multi", variant="fp32")`. In REST,
|
|
252
|
+
quantizations are **model aliases**: use `"model": "gliner2.5-multi@fp32"` in the
|
|
253
|
+
standard `model` field. The base id uses the server/persisted default. There is
|
|
254
|
+
no `variant` field in the request body; `/v1/models` lists both the base model
|
|
255
|
+
and every alias, and two aliases can be loaded concurrently.
|
|
256
256
|
|
|
257
257
|
A variant becomes default only after passing the parity gate (top-1 ≥ 99%,
|
|
258
258
|
mean |Δp| ≤ 0.02, accuracy delta ≤ 1 pp against the fp32 build on a fixed
|
|
@@ -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.
|
|
24
|
+
uv pip install decision-toolkit # library + CLI (0.4.0 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.
|
|
32
|
+
PyPI: <https://pypi.org/project/decision-toolkit/0.4.0/>. 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
|
|
|
@@ -210,11 +210,11 @@ dtk models current --json # {"current": "...", "variant": "fp32"}
|
|
|
210
210
|
dtk decide --model gliner2.5-multi --variant fp16 --state "..." --q 'cat=choice:a|b'
|
|
211
211
|
```
|
|
212
212
|
|
|
213
|
-
From Python: `DecisionModel("gliner2.5-multi", variant="fp32")`. REST
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
variant
|
|
217
|
-
|
|
213
|
+
From Python: `DecisionModel("gliner2.5-multi", variant="fp32")`. In REST,
|
|
214
|
+
quantizations are **model aliases**: use `"model": "gliner2.5-multi@fp32"` in the
|
|
215
|
+
standard `model` field. The base id uses the server/persisted default. There is
|
|
216
|
+
no `variant` field in the request body; `/v1/models` lists both the base model
|
|
217
|
+
and every alias, and two aliases can be loaded concurrently.
|
|
218
218
|
|
|
219
219
|
A variant becomes default only after passing the parity gate (top-1 ≥ 99%,
|
|
220
220
|
mean |Δp| ≤ 0.02, accuracy delta ≤ 1 pp against the fp32 build on a fixed
|
|
@@ -165,7 +165,8 @@ curl -s http://127.0.0.1:8000/v1/decisions \
|
|
|
165
165
|
}' | jq
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
-
`variant`
|
|
168
|
+
Use the model alias `id@variant` for a specific quantization; the base id uses
|
|
169
|
+
the server's default. There is no `variant` field in the request body.
|
|
169
170
|
|
|
170
171
|
### Model per request and auth
|
|
171
172
|
|
|
@@ -176,8 +177,7 @@ curl -s http://127.0.0.1:8000/v1/systemone \
|
|
|
176
177
|
-H "Authorization: Bearer secret" \
|
|
177
178
|
-H "Content-Type: application/json" \
|
|
178
179
|
-d '{
|
|
179
|
-
"model": "gliner2.5-
|
|
180
|
-
"variant": "q4f16",
|
|
180
|
+
"model": "gliner2.5-multi@fp32",
|
|
181
181
|
"state": "I want my money back.",
|
|
182
182
|
"questions": {
|
|
183
183
|
"intent": {"type": "choice", "instructions": "What is the request?",
|
|
@@ -10,7 +10,9 @@ 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 DeBERTa v3 large and Strands Decider ONNX models; `0.3.1` made the catalog list one row per variant with exact commands.
|
|
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; `0.4.0`
|
|
14
|
+
replaced the non-standard REST `variant` body field with standard model aliases
|
|
15
|
+
(`id@variant`).
|
|
14
16
|
|
|
15
17
|
## Local build and verification
|
|
16
18
|
|
|
@@ -37,7 +39,7 @@ Clean install test (no `PYTHONPATH`):
|
|
|
37
39
|
```bash
|
|
38
40
|
uv venv --python 3.12 /tmp/dtk-wheel
|
|
39
41
|
uv pip install --python /tmp/dtk-wheel/bin/python \
|
|
40
|
-
dist/decision_toolkit-0.
|
|
42
|
+
dist/decision_toolkit-0.4.0-py3-none-any.whl
|
|
41
43
|
uv pip check --python /tmp/dtk-wheel/bin/python
|
|
42
44
|
/tmp/dtk-wheel/bin/dtk --version
|
|
43
45
|
/tmp/dtk-wheel/bin/dtk models list --json
|
|
@@ -48,7 +50,7 @@ With inference and server extras:
|
|
|
48
50
|
|
|
49
51
|
```bash
|
|
50
52
|
uv pip install --python /tmp/dtk-wheel/bin/python \
|
|
51
|
-
"dist/decision_toolkit-0.
|
|
53
|
+
"dist/decision_toolkit-0.4.0-py3-none-any.whl[onnx,server,tracing]"
|
|
52
54
|
/tmp/dtk-wheel/bin/dtk decide --model gliner2.5-decide ...
|
|
53
55
|
/tmp/dtk-wheel/bin/dtk serve --model gliner2.5-decide --warmup --port 8016
|
|
54
56
|
curl -s http://127.0.0.1:8016/health
|
|
@@ -82,8 +84,8 @@ No long-lived PyPI token is needed; the workflow uses GitHub OIDC
|
|
|
82
84
|
4. Create and push an annotated tag:
|
|
83
85
|
|
|
84
86
|
```bash
|
|
85
|
-
git tag -a v0.
|
|
86
|
-
git push origin v0.
|
|
87
|
+
git tag -a v0.4.0 -m "decision-toolkit 0.4.0"
|
|
88
|
+
git push origin v0.4.0
|
|
87
89
|
```
|
|
88
90
|
|
|
89
91
|
5. `.github/workflows/release.yml` builds once, publishes to **TestPyPI**, then
|
|
@@ -132,9 +134,9 @@ to TestPyPI without publishing to PyPI or creating a GitHub release.
|
|
|
132
134
|
|
|
133
135
|
## Published release
|
|
134
136
|
|
|
135
|
-
`0.
|
|
137
|
+
`0.4.0` is published through Trusted Publishing on 2026-10-21:
|
|
136
138
|
|
|
137
|
-
<https://pypi.org/project/decision-toolkit/0.
|
|
139
|
+
<https://pypi.org/project/decision-toolkit/0.4.0/>
|
|
138
140
|
|
|
139
141
|
`0.1.0` was the first release; `0.1.1` refreshed the PyPI description; `0.1.2`
|
|
140
142
|
validated the OIDC TestPyPI → PyPI flow; `0.1.3` added post-publish install
|
|
@@ -144,7 +146,8 @@ published to TestPyPI only; `0.1.5` fixed TestPyPI resolution; `0.1.6` added
|
|
|
144
146
|
complete variant/quantization visibility and CLI selection; `0.1.7` aligned
|
|
145
147
|
selection across library, CLI and REST; `0.2.0` corrected the REST conformance
|
|
146
148
|
claims and wire shapes; `0.2.1` changed the public documentation URLs; `0.3.0`
|
|
147
|
-
added the three new ONNX decision models; `0.3.1` made the catalog list one row per variant.
|
|
149
|
+
added the three new ONNX decision models; `0.3.1` made the catalog list one row per variant; `0.4.0` moved REST variant
|
|
150
|
+
selection to standard model aliases.
|
|
148
151
|
|
|
149
152
|
The tag-triggered workflow remains the preferred path for future releases once
|
|
150
153
|
the TestPyPI/PyPI trusted publishers and protected environments are configured.
|
|
@@ -49,25 +49,25 @@ limitations listed below.
|
|
|
49
49
|
Toolkit-only metadata is under `x_decision_toolkit`, never mixed into standard
|
|
50
50
|
fields. `/v1/decision-models` is the rich, non-standard catalog endpoint.
|
|
51
51
|
|
|
52
|
-
## Variants
|
|
53
|
-
|
|
54
|
-
Neither TypeSafe nor OpenAI has a `variant` request field
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
`/v1/models
|
|
68
|
-
expose the
|
|
69
|
-
|
|
70
|
-
|
|
52
|
+
## Variants as model aliases
|
|
53
|
+
|
|
54
|
+
Neither TypeSafe nor OpenAI has a `variant` request field. The toolkit therefore
|
|
55
|
+
publishes each quantization as a **model alias**:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{"model": "gliner2.5-multi@fp32", "state": "...", "questions": {...}}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The `model` field is the standard field. `gliner2.5-multi` uses the server's
|
|
62
|
+
default (or the persisted `dtk models use` selection); `gliner2.5-multi@fp32`
|
|
63
|
+
selects that exact variant. Both aliases are listed by `/v1/models`, and the
|
|
64
|
+
registry loads them in separate slots, so two variants of one base model can be
|
|
65
|
+
used by the same server process.
|
|
66
|
+
|
|
67
|
+
`/v1/models/gliner2.5-multi@fp32`, `/v1/decision-models`, `/v1/info` and `/ready`
|
|
68
|
+
expose the alias, variant, default, cached state and current selection. The
|
|
69
|
+
response metadata under `x_decision_toolkit.variant` is an extension; the
|
|
70
|
+
request body remains standard. See [Variants and quantization](VARIANTS.md).
|
|
71
71
|
|
|
72
72
|
## System One (TypeSafe API schema 0.2.0)
|
|
73
73
|
|
|
@@ -45,8 +45,8 @@ the parity, hash and license gates for this catalog.
|
|
|
45
45
|
The same catalog variant is used by the library, CLI and REST API. Selection
|
|
46
46
|
precedence is:
|
|
47
47
|
|
|
48
|
-
1. an explicit per-call
|
|
49
|
-
|
|
48
|
+
1. an explicit per-call variant in the library or CLI
|
|
49
|
+
(`DecisionModel(..., variant=...)`, `--variant`);
|
|
50
50
|
2. the CLI/server configuration (`dtk models use`, or `dtk serve --variant`);
|
|
51
51
|
3. the catalog default marked with `*`.
|
|
52
52
|
|
|
@@ -54,17 +54,18 @@ precedence is:
|
|
|
54
54
|
| --- | --- | --- |
|
|
55
55
|
| Library | `DecisionModel("gliner2.5-multi", variant="fp32")` | persisted variant for the current model, else catalog default |
|
|
56
56
|
| CLI | `--variant fp32` | variant selected by `dtk models use`, else catalog default |
|
|
57
|
-
| REST
|
|
57
|
+
| REST | `"model": "gliner2.5-multi@fp32"` (model alias) | base model id; server `--variant`/persisted default |
|
|
58
58
|
|
|
59
59
|
`DecisionModel.variant` and the CLI report the selected variant (`id@variant` in
|
|
60
60
|
`dtk models current`). REST responses expose it under the namespaced
|
|
61
61
|
`x_decision_toolkit.variant` extension; `/v1/decision-models` includes
|
|
62
62
|
`current` and `current_variant`, plus all `variants` and `cached_variants`.
|
|
63
|
-
`variant` is **not** part of TypeSafe or OpenAI
|
|
64
|
-
|
|
63
|
+
`variant` is **not** part of TypeSafe or OpenAI, and standard REST clients must
|
|
64
|
+
not send it. They select only `model`; the local server chooses the quantization
|
|
65
|
+
from `--variant` or the persisted default. A server started with
|
|
65
66
|
`--model`/`--variant` reports that default in `/v1/info` and `/ready`.
|
|
66
67
|
|
|
67
|
-
The variant must have been downloaded before a library call or REST
|
|
68
|
+
The variant must have been downloaded before a library call or REST alias
|
|
68
69
|
loads it. An unknown variant returns a model-not-found error; a known but
|
|
69
70
|
missing cache entry returns a model-not-downloaded error.
|
|
70
71
|
|
|
@@ -162,14 +163,18 @@ from decision_toolkit import DecisionModel
|
|
|
162
163
|
model = DecisionModel("gliner2.5-multi", variant="fp32")
|
|
163
164
|
```
|
|
164
165
|
|
|
165
|
-
|
|
166
|
+
For REST, select a quantization through the standard `model` field using the
|
|
167
|
+
alias `id@variant`:
|
|
166
168
|
|
|
167
169
|
```json
|
|
168
|
-
{"model": "gliner2.5-multi", "
|
|
169
|
-
"questions": {"cat": {"type": "choice", "instructions": "What kind?",
|
|
170
|
-
"criteria": {"meeting": null, "other": null}}}}
|
|
170
|
+
{"model": "gliner2.5-multi@fp32", "state": "...", "questions": {}}
|
|
171
171
|
```
|
|
172
172
|
|
|
173
|
+
The base id (`gliner2.5-multi`) uses the server `--variant`/persisted default.
|
|
174
|
+
`/v1/models` lists base models and every alias, and the registry can hold two
|
|
175
|
+
aliases of the same base model in separate slots. Do not add a `variant` field
|
|
176
|
+
to the request body.
|
|
177
|
+
|
|
173
178
|
The variant must already be downloaded. If you name an unknown variant, the
|
|
174
179
|
error lists the catalogued choices, for example:
|
|
175
180
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "decision-toolkit"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
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.
|
|
10
|
+
__version__ = "0.4.0"
|
|
11
11
|
|
|
12
12
|
from .adapters import register_adapter
|
|
13
13
|
from .calibration import brier_score, expected_calibration_error, threshold_sweep
|
|
@@ -703,6 +703,23 @@ def get(model_id: str) -> CatalogModel | None:
|
|
|
703
703
|
return CATALOG_BY_ID.get(model_id)
|
|
704
704
|
|
|
705
705
|
|
|
706
|
+
def parse_alias(model_id: str) -> tuple[str, str | None]:
|
|
707
|
+
"""Split a REST model alias ``catalog-id@variant``.
|
|
708
|
+
|
|
709
|
+
Plain ids and non-catalog paths are returned unchanged. This is the
|
|
710
|
+
standard-compatible way to select a quantization: the OpenAI/TypeSafe
|
|
711
|
+
``model`` field remains a single string; no non-standard ``variant`` body
|
|
712
|
+
field is needed.
|
|
713
|
+
"""
|
|
714
|
+
if "@" not in model_id:
|
|
715
|
+
return model_id, None
|
|
716
|
+
base, variant_name = model_id.rsplit("@", 1)
|
|
717
|
+
model = get(base)
|
|
718
|
+
if model is not None and any(variant.name == variant_name for variant in model.variants):
|
|
719
|
+
return base, variant_name
|
|
720
|
+
return model_id, None
|
|
721
|
+
|
|
722
|
+
|
|
706
723
|
def select_variant(model: CatalogModel, name: str | None = None) -> Variant:
|
|
707
724
|
"""Choose a variant by name, or the model's default."""
|
|
708
725
|
if name is None:
|
|
@@ -732,5 +749,6 @@ __all__ = [
|
|
|
732
749
|
"ModelInfo",
|
|
733
750
|
"Variant",
|
|
734
751
|
"get",
|
|
752
|
+
"parse_alias",
|
|
735
753
|
"select_variant",
|
|
736
754
|
]
|
|
@@ -72,7 +72,7 @@ class OpenAIDecisionsRequest(BaseModel):
|
|
|
72
72
|
min_length=1, max_length=MAX_QUESTIONS
|
|
73
73
|
)
|
|
74
74
|
model: str | None = None
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
@model_validator(mode="after")
|
|
77
77
|
def _validate_input(self) -> OpenAIDecisionsRequest:
|
|
78
78
|
if self.input is None:
|
{decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/contracts/systemone_v1.py
RENAMED
|
@@ -117,7 +117,6 @@ class SystemOneRequest(BaseModel):
|
|
|
117
117
|
files: list[str] | None = None
|
|
118
118
|
images: list[str] | None = None
|
|
119
119
|
model: str | None = None
|
|
120
|
-
variant: str | None = None
|
|
121
120
|
|
|
122
121
|
@model_validator(mode="after")
|
|
123
122
|
def _validate_state(self) -> SystemOneRequest:
|
|
@@ -165,6 +165,14 @@ class ModelRegistry:
|
|
|
165
165
|
raise ModelNotFoundError(
|
|
166
166
|
"no model configured; pass `model` or set one with `dtk models use`"
|
|
167
167
|
)
|
|
168
|
+
base_identifier, alias_variant = catalog.parse_alias(identifier)
|
|
169
|
+
if alias_variant is not None:
|
|
170
|
+
identifier = base_identifier
|
|
171
|
+
if variant is not None and variant != alias_variant:
|
|
172
|
+
raise ModelNotFoundError(
|
|
173
|
+
f"model alias selects variant {alias_variant!r}, not {variant!r}"
|
|
174
|
+
)
|
|
175
|
+
variant = alias_variant
|
|
168
176
|
effective_variant = variant
|
|
169
177
|
if effective_variant is None and identifier == self.default_identifier:
|
|
170
178
|
effective_variant = self.default_variant
|
|
@@ -378,6 +378,7 @@ def _rich_model_payload(
|
|
|
378
378
|
*,
|
|
379
379
|
current: str | None,
|
|
380
380
|
current_variant: str | None = None,
|
|
381
|
+
selected_variant: catalog.Variant | None = None,
|
|
381
382
|
) -> dict[str, Any]:
|
|
382
383
|
payload = model.info.to_dict()
|
|
383
384
|
payload["cached_variants"] = [
|
|
@@ -385,12 +386,38 @@ def _rich_model_payload(
|
|
|
385
386
|
]
|
|
386
387
|
payload["current"] = model.id == current
|
|
387
388
|
payload["current_variant"] = current_variant if model.id == current else None
|
|
389
|
+
payload["base_model"] = model.id
|
|
390
|
+
if selected_variant is not None:
|
|
391
|
+
payload["selected_variant"] = selected_variant.name
|
|
392
|
+
payload["selected_quant"] = selected_variant.quant
|
|
388
393
|
payload["object"] = "model"
|
|
389
394
|
payload["owned_by"] = "decision-toolkit"
|
|
390
395
|
payload["created"] = 0
|
|
391
396
|
return payload
|
|
392
397
|
|
|
393
398
|
|
|
399
|
+
def _alias_payload(
|
|
400
|
+
model: catalog.CatalogModel,
|
|
401
|
+
variant: catalog.Variant,
|
|
402
|
+
cached: set[tuple[str, str]],
|
|
403
|
+
*,
|
|
404
|
+
current: str | None,
|
|
405
|
+
current_variant: str | None,
|
|
406
|
+
) -> dict[str, Any]:
|
|
407
|
+
"""OpenAI-shaped entry for the standard ``model`` alias ``id@variant``."""
|
|
408
|
+
payload = _rich_model_payload(
|
|
409
|
+
model,
|
|
410
|
+
cached,
|
|
411
|
+
current=current,
|
|
412
|
+
current_variant=current_variant,
|
|
413
|
+
selected_variant=variant,
|
|
414
|
+
)
|
|
415
|
+
payload["id"] = f"{model.id}@{variant.name}"
|
|
416
|
+
payload["name"] = f"{model.name} [{variant.name}]"
|
|
417
|
+
payload["alias"] = True
|
|
418
|
+
return payload
|
|
419
|
+
|
|
420
|
+
|
|
394
421
|
def _cached_custom_payload(entry: Any) -> dict[str, Any]:
|
|
395
422
|
return {
|
|
396
423
|
"id": entry.identifier,
|
|
@@ -689,21 +716,35 @@ def create_app(
|
|
|
689
716
|
@app.get("/v1/models", tags=["models"], dependencies=protected)
|
|
690
717
|
def models() -> dict[str, Any]:
|
|
691
718
|
_store, cached, current, current_variant = catalog_state()
|
|
692
|
-
data = [
|
|
693
|
-
|
|
694
|
-
|
|
719
|
+
data = []
|
|
720
|
+
for catalog_model in catalog.CATALOG:
|
|
721
|
+
data.append({
|
|
722
|
+
"id": catalog_model.id,
|
|
695
723
|
"object": "model",
|
|
696
724
|
"created": 0,
|
|
697
725
|
"owned_by": "decision-toolkit",
|
|
698
726
|
"x_decision_toolkit": _rich_model_payload(
|
|
699
|
-
|
|
727
|
+
catalog_model,
|
|
700
728
|
cached,
|
|
701
729
|
current=current,
|
|
702
730
|
current_variant=current_variant,
|
|
703
731
|
),
|
|
704
|
-
}
|
|
705
|
-
for
|
|
706
|
-
|
|
732
|
+
})
|
|
733
|
+
for catalog_variant in catalog_model.variants:
|
|
734
|
+
rich = _alias_payload(
|
|
735
|
+
catalog_model,
|
|
736
|
+
catalog_variant,
|
|
737
|
+
cached,
|
|
738
|
+
current=current,
|
|
739
|
+
current_variant=current_variant,
|
|
740
|
+
)
|
|
741
|
+
data.append({
|
|
742
|
+
"id": rich["id"],
|
|
743
|
+
"object": "model",
|
|
744
|
+
"created": 0,
|
|
745
|
+
"owned_by": "decision-toolkit",
|
|
746
|
+
"x_decision_toolkit": rich,
|
|
747
|
+
})
|
|
707
748
|
known = {model.id for model in catalog.CATALOG}
|
|
708
749
|
for entry in _store.entries():
|
|
709
750
|
if entry.identifier not in known:
|
|
@@ -714,16 +755,28 @@ def create_app(
|
|
|
714
755
|
@app.get("/v1/models/{model_name:path}", tags=["models"], dependencies=protected)
|
|
715
756
|
def model_detail(model_name: str) -> dict[str, Any]:
|
|
716
757
|
_store, cached, current, current_variant = catalog_state()
|
|
717
|
-
|
|
758
|
+
base_name, alias_variant = catalog.parse_alias(model_name)
|
|
759
|
+
model = catalog.get(base_name)
|
|
718
760
|
if model is not None:
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
761
|
+
selected = catalog.select_variant(model, alias_variant) if alias_variant else None
|
|
762
|
+
rich = (
|
|
763
|
+
_alias_payload(
|
|
764
|
+
model,
|
|
765
|
+
selected,
|
|
766
|
+
cached,
|
|
767
|
+
current=current,
|
|
768
|
+
current_variant=current_variant,
|
|
769
|
+
)
|
|
770
|
+
if selected is not None
|
|
771
|
+
else _rich_model_payload(
|
|
772
|
+
model,
|
|
773
|
+
cached,
|
|
774
|
+
current=current,
|
|
775
|
+
current_variant=current_variant,
|
|
776
|
+
)
|
|
724
777
|
)
|
|
725
778
|
return {
|
|
726
|
-
"id":
|
|
779
|
+
"id": rich["id"],
|
|
727
780
|
"object": "model",
|
|
728
781
|
"created": 0,
|
|
729
782
|
"owned_by": "decision-toolkit",
|
|
@@ -782,7 +835,7 @@ def create_app(
|
|
|
782
835
|
"in this catalog"
|
|
783
836
|
)
|
|
784
837
|
questions = systemone_questions(payload.questions)
|
|
785
|
-
with registry.acquire(payload.model
|
|
838
|
+
with registry.acquire(payload.model) as selected:
|
|
786
839
|
decision = await run_decision(
|
|
787
840
|
selected,
|
|
788
841
|
payload.state,
|
|
@@ -826,7 +879,7 @@ def create_app(
|
|
|
826
879
|
if len(set(names)) != len(names):
|
|
827
880
|
raise InvalidRequestError("question names must be unique")
|
|
828
881
|
state_text, core_questions, names = openai_to_systemone(payload.input, wire_questions)
|
|
829
|
-
with registry.acquire(payload.model
|
|
882
|
+
with registry.acquire(payload.model) as selected:
|
|
830
883
|
decision = await run_decision(
|
|
831
884
|
selected,
|
|
832
885
|
state_text,
|
|
@@ -140,7 +140,7 @@ def test_rest_default_request_uses_persisted_variant(
|
|
|
140
140
|
assert seen == [("gliner2.5-multi", "fp32")]
|
|
141
141
|
|
|
142
142
|
|
|
143
|
-
def
|
|
143
|
+
def test_rest_model_alias_selects_a_variant(monkeypatch, home):
|
|
144
144
|
from decision_toolkit import registry as registry_module
|
|
145
145
|
|
|
146
146
|
seen: list[tuple[str | None, str | None]] = []
|
|
@@ -152,7 +152,8 @@ def test_rest_explicit_variant_is_passed_to_the_model(monkeypatch, home):
|
|
|
152
152
|
monkeypatch.setattr(registry_module, "DecisionModel", fake_model)
|
|
153
153
|
app = create_app(model_id="gliner2.5-multi", home=str(home))
|
|
154
154
|
response = TestClient(app).post(
|
|
155
|
-
"/v1/systemone",
|
|
155
|
+
"/v1/systemone",
|
|
156
|
+
json=_systemone_body(model="gliner2.5-multi@fp32"),
|
|
156
157
|
)
|
|
157
158
|
assert response.status_code == 200
|
|
158
159
|
assert response.json()["x_decision_toolkit"]["variant"] == "fp32"
|
|
@@ -174,7 +175,7 @@ def test_rest_openai_request_passes_variant(monkeypatch, home):
|
|
|
174
175
|
"/v1/decisions",
|
|
175
176
|
json={
|
|
176
177
|
"input": "Customer wants a refund.",
|
|
177
|
-
"
|
|
178
|
+
"model": "gliner2.5-multi@fp32",
|
|
178
179
|
"questions": [
|
|
179
180
|
{
|
|
180
181
|
"type": "choice",
|
|
@@ -215,12 +216,42 @@ def test_rest_catalog_exposes_current_variant(home, fake_snapshot):
|
|
|
215
216
|
assert ready.json()["variant"] == "fp32"
|
|
216
217
|
|
|
217
218
|
|
|
218
|
-
def
|
|
219
|
+
def test_rest_loads_two_variants_of_one_model_in_separate_slots(
|
|
220
|
+
monkeypatch, home
|
|
221
|
+
):
|
|
222
|
+
from decision_toolkit import registry as registry_module
|
|
223
|
+
|
|
224
|
+
seen: list[tuple[str | None, str | None]] = []
|
|
225
|
+
|
|
226
|
+
def fake_model(identifier=None, **kwargs):
|
|
227
|
+
seen.append((identifier, kwargs.get("variant")))
|
|
228
|
+
return _VariantModel(kwargs.get("variant") or "fp16")
|
|
229
|
+
|
|
230
|
+
monkeypatch.setattr(registry_module, "DecisionModel", fake_model)
|
|
231
|
+
app = create_app(model_id="gliner2.5-multi", home=str(home))
|
|
232
|
+
client = TestClient(app)
|
|
233
|
+
for alias in ("gliner2.5-multi@fp16", "gliner2.5-multi@fp32"):
|
|
234
|
+
response = client.post(
|
|
235
|
+
"/v1/systemone", json=_systemone_body(model=alias)
|
|
236
|
+
)
|
|
237
|
+
assert response.status_code == 200
|
|
238
|
+
assert seen == [
|
|
239
|
+
("gliner2.5-multi", "fp16"),
|
|
240
|
+
("gliner2.5-multi", "fp32"),
|
|
241
|
+
]
|
|
242
|
+
loaded = app.state.registry.describe()["loaded"]
|
|
243
|
+
assert {item["key"] for item in loaded} == {
|
|
244
|
+
"gliner2.5-multi@fp16",
|
|
245
|
+
"gliner2.5-multi@fp32",
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def test_rest_rejects_the_nonstandard_variant_body_field(client):
|
|
219
250
|
response = client.post(
|
|
220
251
|
"/v1/systemone", json=_systemone_body(variant="fp16")
|
|
221
252
|
)
|
|
222
|
-
assert response.status_code ==
|
|
223
|
-
assert
|
|
253
|
+
assert response.status_code == 422
|
|
254
|
+
assert response.json()["detail"]
|
|
224
255
|
|
|
225
256
|
|
|
226
257
|
# ----------------------------------------------------------------- system one
|
|
@@ -655,6 +686,19 @@ def test_models_detail_and_rich_catalog(client):
|
|
|
655
686
|
assert entry["capabilities"]["max_options"] == 255
|
|
656
687
|
|
|
657
688
|
|
|
689
|
+
def test_models_endpoint_lists_variant_aliases(client):
|
|
690
|
+
payload = client.get("/v1/models").json()
|
|
691
|
+
by_id = {item["id"]: item for item in payload["data"]}
|
|
692
|
+
assert "gliner2.5-multi" in by_id
|
|
693
|
+
assert "gliner2.5-multi@fp16" in by_id
|
|
694
|
+
assert "gliner2.5-multi@fp32" in by_id
|
|
695
|
+
alias = by_id["gliner2.5-multi@fp32"]
|
|
696
|
+
assert alias["x_decision_toolkit"]["selected_variant"] == "fp32"
|
|
697
|
+
detail = client.get("/v1/models/gliner2.5-multi@fp32").json()
|
|
698
|
+
assert detail["id"] == "gliner2.5-multi@fp32"
|
|
699
|
+
assert detail["x_decision_toolkit"]["selected_variant"] == "fp32"
|
|
700
|
+
|
|
701
|
+
|
|
658
702
|
def test_openai_sdk_can_list_models(client):
|
|
659
703
|
openai = pytest.importorskip("openai")
|
|
660
704
|
|
|
@@ -723,9 +767,9 @@ def test_per_request_model_selection_uses_the_registry(monkeypatch, home):
|
|
|
723
767
|
"/v1/systemone", json=_systemone_body(model="alpha")
|
|
724
768
|
).status_code == 200
|
|
725
769
|
assert client.post(
|
|
726
|
-
"/v1/systemone", json=_systemone_body(model="
|
|
770
|
+
"/v1/systemone", json=_systemone_body(model="gliner2.5-multi@fp32")
|
|
727
771
|
).status_code == 200
|
|
728
772
|
loaded = app.state.registry.describe()["loaded"]
|
|
729
773
|
keys = {item["key"] for item in loaded}
|
|
730
774
|
assert "alpha@" in keys
|
|
731
|
-
assert "
|
|
775
|
+
assert "gliner2.5-multi@fp32" in keys
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/adapters/gliner2_decide.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/adapters/opendecider.py
RENAMED
|
File without changes
|
|
File without changes
|
{decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/adapters/strands_decider.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{decision_toolkit-0.3.1 → decision_toolkit-0.4.0}/src/decision_toolkit/contracts/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|