noulxp 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.
- noulxp-0.4.0/.gitignore +14 -0
- noulxp-0.4.0/CHANGELOG.md +165 -0
- noulxp-0.4.0/CONTRIBUTING.md +50 -0
- noulxp-0.4.0/LICENSE +176 -0
- noulxp-0.4.0/NOTICE +21 -0
- noulxp-0.4.0/PAPER.md +74 -0
- noulxp-0.4.0/PKG-INFO +353 -0
- noulxp-0.4.0/README.md +303 -0
- noulxp-0.4.0/RELEASING.md +72 -0
- noulxp-0.4.0/SPEC.md +839 -0
- noulxp-0.4.0/VALIDATION.md +237 -0
- noulxp-0.4.0/badge/BADGE.md +51 -0
- noulxp-0.4.0/badge/noulxp-compatible.svg +12 -0
- noulxp-0.4.0/badge/noulxp-portable.svg +12 -0
- noulxp-0.4.0/legacy/opendxp/README.md +16 -0
- noulxp-0.4.0/legacy/opendxp/pyproject.toml +40 -0
- noulxp-0.4.0/legacy/opendxp/src/opendxp/__init__.py +49 -0
- noulxp-0.4.0/legacy/opendxp/src/opendxp/__main__.py +5 -0
- noulxp-0.4.0/legacy/opendxp/src/opendxp_cli.py +12 -0
- noulxp-0.4.0/pyproject.toml +87 -0
- noulxp-0.4.0/schemas/calibration.schema.json +34 -0
- noulxp-0.4.0/schemas/check-report.schema.json +41 -0
- noulxp-0.4.0/schemas/conformance-case.schema.json +42 -0
- noulxp-0.4.0/schemas/error.schema.json +29 -0
- noulxp-0.4.0/schemas/models.schema.json +51 -0
- noulxp-0.4.0/schemas/noulxp.schema.json +101 -0
- noulxp-0.4.0/schemas/prompt.schema.json +191 -0
- noulxp-0.4.0/schemas/request.schema.json +62 -0
- noulxp-0.4.0/schemas/response.schema.json +56 -0
- noulxp-0.4.0/schemas/template.schema.json +98 -0
- noulxp-0.4.0/scripts/anyjev_token_ids.py +90 -0
- noulxp-0.4.0/scripts/build_requests.py +862 -0
- noulxp-0.4.0/scripts/decider_token_ids.py +59 -0
- noulxp-0.4.0/scripts/julia_parity.py +71 -0
- noulxp-0.4.0/scripts/llama_numerics.py +105 -0
- noulxp-0.4.0/scripts/prefix_sharing.py +152 -0
- noulxp-0.4.0/src/noulxp/__init__.py +26 -0
- noulxp-0.4.0/src/noulxp/__main__.py +3 -0
- noulxp-0.4.0/src/noulxp/answers.py +96 -0
- noulxp-0.4.0/src/noulxp/bench.py +441 -0
- noulxp-0.4.0/src/noulxp/calibrate.py +429 -0
- noulxp-0.4.0/src/noulxp/calibration.py +112 -0
- noulxp-0.4.0/src/noulxp/cli.py +543 -0
- noulxp-0.4.0/src/noulxp/conformance.py +349 -0
- noulxp-0.4.0/src/noulxp/data/requests-0.1.jsonl +52 -0
- noulxp-0.4.0/src/noulxp/errors.py +23 -0
- noulxp-0.4.0/src/noulxp/export/__init__.py +7 -0
- noulxp-0.4.0/src/noulxp/export/anyjev.py +279 -0
- noulxp-0.4.0/src/noulxp/export/common.py +118 -0
- noulxp-0.4.0/src/noulxp/export/decider.py +169 -0
- noulxp-0.4.0/src/noulxp/export/encoder.py +105 -0
- noulxp-0.4.0/src/noulxp/export/julia.py +383 -0
- noulxp-0.4.0/src/noulxp/export/laya.py +251 -0
- noulxp-0.4.0/src/noulxp/export/onnx_graph.py +249 -0
- noulxp-0.4.0/src/noulxp/mcp.py +257 -0
- noulxp-0.4.0/src/noulxp/native/__init__.py +145 -0
- noulxp-0.4.0/src/noulxp/native/anyjev.py +120 -0
- noulxp-0.4.0/src/noulxp/native/decider.py +348 -0
- noulxp-0.4.0/src/noulxp/native/julia.py +317 -0
- noulxp-0.4.0/src/noulxp/package.py +159 -0
- noulxp-0.4.0/src/noulxp/profiles/__init__.py +0 -0
- noulxp-0.4.0/src/noulxp/profiles/causal_letters.py +632 -0
- noulxp-0.4.0/src/noulxp/profiles/encoder_markers.py +516 -0
- noulxp-0.4.0/src/noulxp/profiles/typed.py +298 -0
- noulxp-0.4.0/src/noulxp/providers.py +190 -0
- noulxp-0.4.0/src/noulxp/request.py +114 -0
- noulxp-0.4.0/src/noulxp/rotations.py +77 -0
- noulxp-0.4.0/src/noulxp/runtime.py +45 -0
- noulxp-0.4.0/src/noulxp/schemas.py +50 -0
- noulxp-0.4.0/src/noulxp/server.py +205 -0
- noulxp-0.4.0/src/noulxp/serving.py +291 -0
- noulxp-0.4.0/src/noulxp/spec.py +89 -0
- noulxp-0.4.0/src/noulxp/text.py +103 -0
- noulxp-0.4.0/src/noulxp/tokens.py +39 -0
- noulxp-0.4.0/src/noulxp/validate.py +73 -0
- noulxp-0.4.0/tests/conftest.py +46 -0
- noulxp-0.4.0/tests/generators.py +70 -0
- noulxp-0.4.0/tests/oracles.py +299 -0
- noulxp-0.4.0/tests/test_answers.py +65 -0
- noulxp-0.4.0/tests/test_attention.py +83 -0
- noulxp-0.4.0/tests/test_bench.py +123 -0
- noulxp-0.4.0/tests/test_calibrate.py +294 -0
- noulxp-0.4.0/tests/test_calibration.py +69 -0
- noulxp-0.4.0/tests/test_conformance.py +346 -0
- noulxp-0.4.0/tests/test_mcp.py +206 -0
- noulxp-0.4.0/tests/test_official_mapping.py +96 -0
- noulxp-0.4.0/tests/test_prompt.py +133 -0
- noulxp-0.4.0/tests/test_providers.py +71 -0
- noulxp-0.4.0/tests/test_request.py +57 -0
- noulxp-0.4.0/tests/test_schemas.py +115 -0
- noulxp-0.4.0/tests/test_serving.py +347 -0
- noulxp-0.4.0/tests/test_spec.py +13 -0
- noulxp-0.4.0/tests/test_template.py +134 -0
- noulxp-0.4.0/tests/test_text.py +25 -0
- noulxp-0.4.0/tests/test_typed.py +528 -0
- noulxp-0.4.0/validation/anyjev-qwen3-1.7b/calibration.json +11 -0
- noulxp-0.4.0/validation/anyjev-qwen3-1.7b/check-cpu-default-decode.json +128 -0
- noulxp-0.4.0/validation/anyjev-qwen3-1.7b/check-cpu-q8_0.json +352 -0
- noulxp-0.4.0/validation/anyjev-qwen3-1.7b/check-cpu.json +113 -0
- noulxp-0.4.0/validation/anyjev-qwen3-1.7b/conformance.jsonl +52 -0
- noulxp-0.4.0/validation/anyjev-qwen3-1.7b/odxp.json +76 -0
- noulxp-0.4.0/validation/anyjev-qwen3-1.7b/prompt.json +158 -0
- noulxp-0.4.0/validation/anyjev-qwen3-1.7b/token-ids.json +6 -0
- noulxp-0.4.0/validation/decider-2b/calibration.json +18 -0
- noulxp-0.4.0/validation/decider-2b/check-cpu.json +113 -0
- noulxp-0.4.0/validation/decider-2b/check-metal.json +240 -0
- noulxp-0.4.0/validation/decider-2b/conformance.jsonl +52 -0
- noulxp-0.4.0/validation/decider-2b/llama-numerics.json +20 -0
- noulxp-0.4.0/validation/decider-2b/odxp.json +67 -0
- noulxp-0.4.0/validation/decider-2b/prefix-sharing-cpu.json +18 -0
- noulxp-0.4.0/validation/decider-2b/prefix-sharing-metal.json +18 -0
- noulxp-0.4.0/validation/decider-2b/prompt.json +324 -0
- noulxp-0.4.0/validation/decider-2b/token-ids.json +1 -0
- noulxp-0.4.0/validation/julia-1/calibration.json +9 -0
- noulxp-0.4.0/validation/julia-1/check-coreml.json +110 -0
- noulxp-0.4.0/validation/julia-1/check-cpu.json +109 -0
- noulxp-0.4.0/validation/julia-1/conformance.jsonl +52 -0
- noulxp-0.4.0/validation/julia-1/odxp.json +86 -0
- noulxp-0.4.0/validation/julia-1/parity-cpu.json +1 -0
- noulxp-0.4.0/validation/julia-1/template.json +69 -0
- noulxp-0.4.0/validation/julia-1-official/calibration.json +9 -0
- noulxp-0.4.0/validation/julia-1-official/check-cpu.json +109 -0
- noulxp-0.4.0/validation/julia-1-official/conformance.jsonl +52 -0
- noulxp-0.4.0/validation/julia-1-official/odxp.json +92 -0
- noulxp-0.4.0/validation/julia-1-official/parity-cpu.json +1 -0
- noulxp-0.4.0/validation/julia-1-official/template.json +69 -0
- noulxp-0.4.0/validation/laya-main/calibration.json +66 -0
- noulxp-0.4.0/validation/laya-main/check-cpu.json +109 -0
- noulxp-0.4.0/validation/laya-main/conformance.jsonl +52 -0
- noulxp-0.4.0/validation/laya-main/odxp.json +86 -0
- noulxp-0.4.0/validation/laya-main/template.json +69 -0
- noulxp-0.4.0/validation/laya-multilingual/calibration.json +20 -0
- noulxp-0.4.0/validation/laya-multilingual/check-cpu.json +109 -0
- noulxp-0.4.0/validation/laya-multilingual/conformance.jsonl +52 -0
- noulxp-0.4.0/validation/laya-multilingual/odxp.json +86 -0
- noulxp-0.4.0/validation/laya-multilingual/template.json +69 -0
- noulxp-0.4.0/validation/laya-typed-decisions/calibration.json +66 -0
- noulxp-0.4.0/validation/laya-typed-decisions/check-cpu.json +109 -0
- noulxp-0.4.0/validation/laya-typed-decisions/conformance.jsonl +52 -0
- noulxp-0.4.0/validation/laya-typed-decisions/odxp.json +86 -0
- noulxp-0.4.0/validation/laya-typed-decisions/template.json +69 -0
noulxp-0.4.0/.gitignore
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.4.0 (2026-09-30)
|
|
4
|
+
|
|
5
|
+
- **OpenDXP is now NoulXP.** Another open-source project already used the name
|
|
6
|
+
OpenDXP, so the standard, the package, the command and the badge take a name
|
|
7
|
+
of their own: `pip install noulxp`, `noulxp serve`, `noulxp check`, the
|
|
8
|
+
manifest `noulxp.json`, the versions `noulxp/0.1` and `noulxp/0.2`, and the
|
|
9
|
+
badge "NoulXP compatible". The format, the answers and the protocol are those
|
|
10
|
+
of 0.3.1.
|
|
11
|
+
- Packages made before the rename run as they did: a runtime reads `odxp.json`
|
|
12
|
+
when a package has no `noulxp.json`, and `odxp/0.1` and `odxp/0.2` as the same
|
|
13
|
+
versions under the old name. Converters write only the new names.
|
|
14
|
+
- The HTTP binding's header is `NoulXP-Version` (was `OpenDXP-Version`) and the
|
|
15
|
+
MCP server calls itself `noulxp`. `NOULXP_TOKEN` replaces `OPENDXP_TOKEN`,
|
|
16
|
+
which is still read.
|
|
17
|
+
- `opendxp` on PyPI is now a redirect: `pip install opendxp` installs `noulxp`,
|
|
18
|
+
`import opendxp` (and every `opendxp.*` module) is `noulxp`, and the `opendxp`
|
|
19
|
+
command runs `noulxp`, each with a note to switch.
|
|
20
|
+
|
|
21
|
+
## 0.3.1 (2026-09-30)
|
|
22
|
+
|
|
23
|
+
- **Fixed: `opendxp serve` answered no faster than ~40 ms a request on Linux.**
|
|
24
|
+
An answer's headers and body left in two writes with Nagle's algorithm on, so
|
|
25
|
+
on a kept-alive connection the body waited for the client's delayed ACK of
|
|
26
|
+
the headers. Answers now leave in one write, with `TCP_NODELAY`. Julia 1 on an
|
|
27
|
+
NVIDIA A40, one client: 27.6 decisions/s (p50 62 ms) before, 161.6 (p50
|
|
28
|
+
7.5 ms) after. macOS was not affected.
|
|
29
|
+
- **`opendxp serve` reads the requests that wait together** (`--batch N`,
|
|
30
|
+
default 32; 1 answers one at a time as before). A request that finds its
|
|
31
|
+
model idle is read at once, in its own thread, as `predict` reads it; requests
|
|
32
|
+
that arrive while the model reads queue, and one thread reads them together
|
|
33
|
+
(`predict_many`). On an A40 at 64 clients, Julia 1 answered 262 decisions/s
|
|
34
|
+
(78 one at a time; 300 with fused attention), Laya multilingual 191 (87);
|
|
35
|
+
one client, 178 (p50 6 ms). `--batch-rows` decodes a causal-letters
|
|
36
|
+
package's rows together (AnyJev at one client: p50 119 to 66 ms).
|
|
37
|
+
- The server's listen backlog is 128; it was socketserver's 5, past which a
|
|
38
|
+
burst of new clients was reset.
|
|
39
|
+
- `opendxp bench`'s HTTP client turns Nagle's algorithm off, as curl, requests
|
|
40
|
+
and browsers do: http.client sends a request's headers and body apart.
|
|
41
|
+
- Requests are validated with one compiled validator per schema, not a new one
|
|
42
|
+
per request.
|
|
43
|
+
- **`opendxp export --opset 23`** (laya, julia): attention as ONNX's fused
|
|
44
|
+
`Attention` operator instead of a chain of small ones, with the mask expanded
|
|
45
|
+
to the shape onnxruntime's kernels take. On an A40 through onnxruntime 1.30,
|
|
46
|
+
6 to 14% more decisions per second one request at a time (Julia 1: 199 to
|
|
47
|
+
210); on an x86 server CPU 1.6 to 2.0 times; on an Apple M4 CPU, Julia 1 from
|
|
48
|
+
26.1 to 30.9. onnxruntime runs the operator on CUDA from 1.30: the runtime
|
|
49
|
+
refuses such a package on CUDA with an older onnxruntime rather than let
|
|
50
|
+
attention fall back to the CPU. encoder-markers reads the opset from the
|
|
51
|
+
manifest's weights entry.
|
|
52
|
+
|
|
53
|
+
## 0.3.0 (2026-09-30)
|
|
54
|
+
|
|
55
|
+
- **`opendxp calibrate`** (SPEC.md 7.1): fits a package's temperatures, one per
|
|
56
|
+
question type, to labelled requests (an option's key, a distribution, or an
|
|
57
|
+
answer object per question) and writes a calibration.json, with accuracy, KL,
|
|
58
|
+
Brier and ECE before and after, on the labels and on `--test`. The model is
|
|
59
|
+
read once; each temperature is the least mean KL(label || answer), from a
|
|
60
|
+
log-spaced grid refined by golden-section search. On the typed-decisions test
|
|
61
|
+
split, 50 held-out requests labelled with one option each brought Julia 1's
|
|
62
|
+
mean confidence from 0.96 to 0.72, its accuracy (ECE 0.236 to 0.044), and the
|
|
63
|
+
benchmark's distributions took its KL from the gold from 2.78 to 0.23, with
|
|
64
|
+
the same decisions. `--hard-labels` fits to each label's leading option, to
|
|
65
|
+
how often the model is right, when the labels are distributions.
|
|
66
|
+
- **`--calibration FILE`** on `run`, `serve`, `mcp` and `bench`, and
|
|
67
|
+
`load(..., calibration=...)`: answer with another calibration.json than the
|
|
68
|
+
package's. The package's conformance file is still replayed at its own
|
|
69
|
+
(`conformance.replay` included), discovery names the file by its sha256, and
|
|
70
|
+
reports say `"calibration": "package"` otherwise.
|
|
71
|
+
- Runtimes have `readouts(items)` (each request read once, answered at any
|
|
72
|
+
calibration) and `distributions(..., calibration)`.
|
|
73
|
+
- Fixed: the cache of content-free priors was keyed without the temperature, so
|
|
74
|
+
a runtime answering at two calibrations reused a prior read at the other.
|
|
75
|
+
|
|
76
|
+
- **`opendxp bench`**: how fast a package (the reference runtime, in this
|
|
77
|
+
process) or any OpenDXP server (over the HTTP binding, at several concurrency
|
|
78
|
+
levels) answers: requests and decisions per second, latency percentiles,
|
|
79
|
+
errors by status and, with `--usd-per-hour`, the cost per 1,000 decisions.
|
|
80
|
+
Its clients back off on 429 and 503 as real ones do. Standard library only.
|
|
81
|
+
- **Rows read together** (causal-letters): `batch_rows` decodes up to that many
|
|
82
|
+
rows (a request's questions and rotations) in one llama.cpp call, each its
|
|
83
|
+
own sequence from empty memory; `batch_cache` shares one cache among them or
|
|
84
|
+
gives each its own (`per-row`). It is a serving choice, not part of a package:
|
|
85
|
+
`opendxp check --batch-rows N` says whether it keeps a package compatible on
|
|
86
|
+
a given machine. `predict_many` answers several requests' rows together.
|
|
87
|
+
- A request's rows are planned before any is read (typed layouts included),
|
|
88
|
+
then combined; the cache of content-free priors is never filled from a
|
|
89
|
+
planning pass.
|
|
90
|
+
- **Requests read together** (encoder-markers): `predict_many` runs several
|
|
91
|
+
requests' questions through the graph in passes of rows of similar length
|
|
92
|
+
(within 1.25 times the shortest, plus 16 tokens; at most 32 rows). Padding is
|
|
93
|
+
masked, so each answer is the one `predict` gives. On an NVIDIA A40, Julia 1's
|
|
94
|
+
89 conformance rows take 243 ms together against 625 ms one at a time; a pass
|
|
95
|
+
filled up to a token budget instead padded short rows to a long one's length
|
|
96
|
+
and was slower than no batching. Static-shape providers (Core ML) answer one
|
|
97
|
+
at a time as before.
|
|
98
|
+
- The ONNX exporter names the graph's dimensions (`batch`, `tokens`, `options`)
|
|
99
|
+
instead of declaring `torch.export.Dim` ranges, which torch 2.8 refused for
|
|
100
|
+
models that treat a dimension of 1 specially.
|
|
101
|
+
- **No silent fallbacks.** An onnxruntime provider asked for by name that does
|
|
102
|
+
not load (a CUDA 13 build on CUDA 12, say) is an error instead of a run on the
|
|
103
|
+
CPU, and reports list the providers that loaded. A causal-letters run on the
|
|
104
|
+
CPU stays there: a GPU build of llama.cpp no longer offloads its matrix
|
|
105
|
+
products (`op_offload`).
|
|
106
|
+
- The encoder converters refuse transformers older than 5.2: 4.57 computes
|
|
107
|
+
ModernBERT differently, and its packages exported without an error, agreed
|
|
108
|
+
with the model they were traced from, and failed their conformance files.
|
|
109
|
+
- **Precision** (SPEC.md 8.1): `precision="exact"` (`--precision exact` on
|
|
110
|
+
check, bench, serve and mcp) asks a GPU for float32 products: ONNX Runtime's
|
|
111
|
+
CUDA provider without TF32, llama.cpp's CUDA and HIP backends accumulating
|
|
112
|
+
F16 and BF16 products in float32. On an NVIDIA A40 every encoder package then
|
|
113
|
+
gives the CPU's numbers (5e-5 instead of up to 0.0067), and AnyJev from its
|
|
114
|
+
BF16 weights passes its conformance file (0.0082 instead of 0.049),
|
|
115
|
+
costing 1 to 50 % of the speed. Reports name the precision they ran at.
|
|
116
|
+
- `conformance.replay` runs a package's conformance file through a runtime that
|
|
117
|
+
is already loaded, so an engine can check a package as it serves it.
|
|
118
|
+
- `opendxp bench` clients keep their connection open between requests, as SDKs
|
|
119
|
+
do.
|
|
120
|
+
- `scripts/prefix_sharing.py` works for every layout: it keeps the last row in
|
|
121
|
+
the cache and decodes only the tokens a row adds.
|
|
122
|
+
|
|
123
|
+
## 0.2.0
|
|
124
|
+
|
|
125
|
+
OpenDXP 0.2: a wire protocol, and models asked in rotation. Every 0.1 package
|
|
126
|
+
still runs, and converters keep writing `odxp/0.1` unless a package needs 0.2.
|
|
127
|
+
|
|
128
|
+
- **HTTP binding** (SPEC.md 11): `POST /v1/systemone`, `GET /v1/models` with
|
|
129
|
+
each model's conformance summary, `GET /healthz`, an error schema, bearer
|
|
130
|
+
tokens and CORS by named origin. `opendxp serve` implements it with the
|
|
131
|
+
standard library and refuses to listen beyond the machine without a token.
|
|
132
|
+
- **MCP binding** (SPEC.md 12): `opendxp mcp` gives every package to AI agents
|
|
133
|
+
as a tool over stdio, with the request and response schemas as its input and
|
|
134
|
+
output schemas. It speaks the current MCP revision (per-request metadata,
|
|
135
|
+
`server/discover`) and the `initialize` handshake of earlier clients.
|
|
136
|
+
- **Typed layouts** (SPEC.md 6.7): a causal-letters prompt can lay out each
|
|
137
|
+
question type on its own (labels by position or attached to their options,
|
|
138
|
+
a listing, a legend for descriptions), inside the model's chat template, each
|
|
139
|
+
row encoded whole. States can be rendered as indented JSON or as a
|
|
140
|
+
conversation, with a text for an empty state (3.2).
|
|
141
|
+
- **Rotations** (SPEC.md 6.8): a question asked once per cyclic shift of its
|
|
142
|
+
options, the shifts combined by log-mean or mean, with an optional
|
|
143
|
+
content-free prior divided out first.
|
|
144
|
+
- `opendxp export anyjev` and `--runtime anyjev`: AnyJev (Nokia) at L0, any
|
|
145
|
+
instruction-tuned model asked the way anyjev 0.2.0 asks it, checked against
|
|
146
|
+
anyjev's own Decider. Validated on Qwen3-1.7B (VALIDATION.md).
|
|
147
|
+
- Packages declare `odxp/0.1` or `odxp/0.2`; this implementation runs both,
|
|
148
|
+
and `opendxp validate` checks that a package's files declare its manifest's
|
|
149
|
+
version.
|
|
150
|
+
|
|
151
|
+
## 0.1.0
|
|
152
|
+
|
|
153
|
+
The first release of OpenDXP, the Open Decision Exchange Protocol, and its
|
|
154
|
+
reference implementation.
|
|
155
|
+
|
|
156
|
+
- The standard, `odxp/0.1`: packages (`odxp.json` and the files it names by
|
|
157
|
+
SHA-256), the `encoder-markers` and `causal-letters` profiles, calibration,
|
|
158
|
+
conformance files and compatibility levels, with JSON Schemas for every file.
|
|
159
|
+
- Reference runtimes on ONNX Runtime and llama.cpp (CPU and GPU builds).
|
|
160
|
+
`--device auto` uses CUDA when available and the CPU otherwise; Core ML,
|
|
161
|
+
OpenVINO, QNN and DirectML are used when named.
|
|
162
|
+
- `opendxp export` for Laya, Julia 1 and Decider; `opendxp conformance
|
|
163
|
+
generate` from the models' own code; `opendxp check`, `validate`, `run` and
|
|
164
|
+
`info`.
|
|
165
|
+
- The OpenDXP 0.1 request set: 52 requests, 91 questions, 11 languages.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Contributing to NoulXP
|
|
2
|
+
|
|
3
|
+
NoulXP is a standard first and code second. A change to what a package means
|
|
4
|
+
is a change to SPEC.md, the schemas and the reference runtime together.
|
|
5
|
+
|
|
6
|
+
## What is most useful
|
|
7
|
+
|
|
8
|
+
- **A model the profiles cannot describe.** Open an issue with the model, the
|
|
9
|
+
exact input construction of its own code, and what `template.json` or
|
|
10
|
+
`prompt.json` would need. This is how the standard grows.
|
|
11
|
+
- **A converter** for another model family (Von, open-jev, Kev, Nimble, ...):
|
|
12
|
+
`src/noulxp/export/<family>.py`, a native adapter in `src/noulxp/native/`
|
|
13
|
+
that runs the model's own code, and the validation results.
|
|
14
|
+
- **Another engine.** The standard is language-neutral. An engine in Rust,
|
|
15
|
+
Go or JavaScript that passes the conformance files of the published
|
|
16
|
+
packages is the strongest test of the spec; report where SPEC.md was
|
|
17
|
+
ambiguous.
|
|
18
|
+
- **Backend results**: `noulxp check --device <backend>` on hardware we do not
|
|
19
|
+
have (CUDA, OpenVINO, QNN, DirectML, ROCm), with the report JSON.
|
|
20
|
+
|
|
21
|
+
## Rules for changes
|
|
22
|
+
|
|
23
|
+
1. **Normative changes** (anything in SPEC.md that uses MUST, SHOULD or MAY,
|
|
24
|
+
the schemas, `src/noulxp/spec.py`) need an issue first, and bump the
|
|
25
|
+
standard's version when they change what an existing package means.
|
|
26
|
+
2. **Conformance files are generated by the model's own code**, never by the
|
|
27
|
+
reference runtime, and record which code and versions produced them. A
|
|
28
|
+
converter that needed model-specific logic in the runtime to pass has not
|
|
29
|
+
passed: move that logic into the declarative files or propose a spec change.
|
|
30
|
+
3. **No invented numbers.** VALIDATION.md and the paper report only what a
|
|
31
|
+
report file in the repository or the packages supports.
|
|
32
|
+
4. **Nothing in a package executes.** No templates with logic, no pickles, no
|
|
33
|
+
`trust_remote_code`.
|
|
34
|
+
|
|
35
|
+
## Development
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
python -m venv .venv && . .venv/bin/activate
|
|
39
|
+
pip install -e ".[dev,onnx]"
|
|
40
|
+
pytest # no downloads; a tokenizer is built in memory
|
|
41
|
+
ruff check src tests scripts && ruff format --check src tests scripts
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The request set lives in `scripts/build_requests.py`; run it to regenerate
|
|
45
|
+
`src/noulxp/data/requests-0.1.jsonl`. Changing it changes the standard's
|
|
46
|
+
conformance set: packages then need their conformance files regenerated.
|
|
47
|
+
|
|
48
|
+
Commits: one logical change each, with a message that says what changed and
|
|
49
|
+
why. Sign-off is not required. By contributing you agree that your
|
|
50
|
+
contribution is licensed under Apache-2.0.
|
noulxp-0.4.0/LICENSE
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
noulxp-0.4.0/NOTICE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
NoulXP, the open exchange protocol for decision models
|
|
2
|
+
Copyright 2026 System One Models
|
|
3
|
+
|
|
4
|
+
This product includes software derived from:
|
|
5
|
+
|
|
6
|
+
- laya (convaiinnovations/laya), Apache-2.0: the input construction reproduced
|
|
7
|
+
declaratively in the Laya converter (laya/common.py build_sequence,
|
|
8
|
+
render_options, clamp_temperature, temp_bucket).
|
|
9
|
+
- Julia 1 (SupersonicLabs/Julia-1, revision a85b127321d580d65176c89ced8273f305745d85),
|
|
10
|
+
Apache-2.0: the JuliaDecisionModel inference subset in noulxp/export/julia.py
|
|
11
|
+
(julia/model.py), the input construction reproduced in its template
|
|
12
|
+
(julia/data.py sequence()), and its inference path rebuilt in
|
|
13
|
+
noulxp/native/julia.py (model.py, data.py, router/engine.py, typed.py).
|
|
14
|
+
- Decider (github.com/Mapika/decider at 23579f7a, decider-ai 1.6.0), Apache-2.0:
|
|
15
|
+
the prompt layout, labels, isolated score levels and temperatures reproduced
|
|
16
|
+
declaratively in the Decider converter (decider/prompt.py, prompt_fast.py,
|
|
17
|
+
systemone.py, temperature.py, engine_gguf.py), and its request rendering,
|
|
18
|
+
prompt construction and GGUF readout rebuilt in noulxp/native/decider.py.
|
|
19
|
+
|
|
20
|
+
NoulXP packages converted from these models carry the models' own weights and
|
|
21
|
+
remain under the models' licences.
|
noulxp-0.4.0/PAPER.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Paper outline
|
|
2
|
+
|
|
3
|
+
Working title: **NoulXP: a portable runtime standard for calibrated
|
|
4
|
+
single-pass decision models**
|
|
5
|
+
|
|
6
|
+
This file tracks the paper: its argument, its sections, and which experiments
|
|
7
|
+
are done. Numbers come from [VALIDATION.md](VALIDATION.md) and are measured,
|
|
8
|
+
never estimated.
|
|
9
|
+
|
|
10
|
+
## The argument
|
|
11
|
+
|
|
12
|
+
1. A new kind of model answers typed questions about a state (choose one of
|
|
13
|
+
these options, score on this scale, is this true) with a calibrated
|
|
14
|
+
probability for every option, in one forward pass. Laya, Julia 1 and
|
|
15
|
+
Decider are three of them, from three teams, with three architectures.
|
|
16
|
+
2. Each ships its own inference code. Running, deploying or comparing them
|
|
17
|
+
means installing, trusting and wrapping each one. Formats such as ONNX and
|
|
18
|
+
GGUF carry the weights but not the rest: how the input is built from the
|
|
19
|
+
request, where the answer is read, how it is calibrated.
|
|
20
|
+
3. NoulXP puts the rest in the package as data (a template or a prompt, and
|
|
21
|
+
temperatures), so one engine runs every model with no code written for it
|
|
22
|
+
and nothing from the package executed.
|
|
23
|
+
4. Faithfulness is testable: the package carries a conformance file of what
|
|
24
|
+
the model's own code answers, and an engine passes when it reproduces it
|
|
25
|
+
within 0.01 with the same decisions.
|
|
26
|
+
5. Two profiles cover the models we know of: bidirectional encoders that
|
|
27
|
+
score a marker token per option, and causal language models read at an
|
|
28
|
+
answer letter.
|
|
29
|
+
|
|
30
|
+
## Sections
|
|
31
|
+
|
|
32
|
+
1. **Introduction.** System One models; the cost of one runtime per model;
|
|
33
|
+
the contribution: the standard, the conformance method, a reference
|
|
34
|
+
implementation and three conversions.
|
|
35
|
+
2. **Background.** Calibrated classification and temperature scaling (Guo et
|
|
36
|
+
al., 2017); marker-based encoders (Laya, Julia 1); letter-probability
|
|
37
|
+
readout from language models (Decider); ONNX and GGUF as weight formats;
|
|
38
|
+
loading model code at run time (`trust_remote_code`) and why a standard
|
|
39
|
+
should not need it.
|
|
40
|
+
3. **The standard.** Requests and answers; packages with nothing executable;
|
|
41
|
+
the two profiles; calibration as data; conformance files and the
|
|
42
|
+
comparison rule; compatibility levels.
|
|
43
|
+
4. **Reference implementation.** Runtimes for both profiles on ONNX Runtime
|
|
44
|
+
and llama.cpp; converters that copy no weights (ONNX external data pointing
|
|
45
|
+
into the published safetensors); conformance generation from the models'
|
|
46
|
+
own code; the System One Engine and the registry, which run packages and
|
|
47
|
+
show the badge.
|
|
48
|
+
5. **Evaluation.** The experiments below.
|
|
49
|
+
6. **Discussion.** What the tolerance means; backend numerics; sharing
|
|
50
|
+
computation versus exactness; what 0.1 leaves open (SPEC.md 14).
|
|
51
|
+
7. **Conclusion.**
|
|
52
|
+
|
|
53
|
+
## Experiments
|
|
54
|
+
|
|
55
|
+
| # | Question | Status |
|
|
56
|
+
| --- | --- | --- |
|
|
57
|
+
| E1 | Do packages reproduce their models' own answers on a CPU? | **Done.** 6 packages, 3 families, 52/52 cases each, all decisions equal, differences at the 4-decimal rounding floor. |
|
|
58
|
+
| E2 | Does a declarative input description give the same tokens as the models' own code? | **Done.** Decider: 149/149 rows identical. Laya and Julia: input construction tested against their own code (tests/). |
|
|
59
|
+
| E3 | Can a model's own ONNX export become a package without exporting again? | **Done.** Julia 1's published graph, renamed and pointed at its checkpoint: 52/52, and 100/100 on its authors' parity cases. |
|
|
60
|
+
| E4 | Do packages stay faithful on accelerator backends? | **Partly.** Julia on Core ML passes (level 3). Decider on Metal keeps every decision but not the probabilities (max 0.036). CUDA, ROCm, OpenVINO, QNN, DirectML to do. |
|
|
61
|
+
| E5 | What moves a causal model's probabilities? | **Done on one machine.** Flash attention off on the CPU: up to 0.014. Metal: 0.036 whatever the attention or cache settings. |
|
|
62
|
+
| E6 | What does sharing the prompt prefix cost in faithfulness? | **Done on one machine.** CPU: 1.8x faster over the set, up to 0.018, and one near-tie decision of 91 changed; Metal: 1.6x faster, nothing added. To repeat on an x86 server. |
|
|
63
|
+
| E7 | What does a package cost? | **Done on one machine.** 3 to 5 MB of graph per encoder package, no weight copies; load and latency per backend. Server numbers to do. |
|
|
64
|
+
| E8 | Is 0.01 the right tolerance? | **To do.** The distribution of differences, and of decision flips, across backends and quantisations. |
|
|
65
|
+
| E9 | Can someone else convert a model from the spec alone? | **To do.** A Laya Studio fine-tune and a model from outside the three families, converted by their authors. |
|
|
66
|
+
|
|
67
|
+
## Before submission
|
|
68
|
+
|
|
69
|
+
- E4, E6 and E7 on an x86 server CPU and at least one NVIDIA GPU.
|
|
70
|
+
- E8 with quantised variants (int8 ONNX, Q4 GGUF) as derived packages.
|
|
71
|
+
- E9 with at least one team outside System One Models.
|
|
72
|
+
- Credit and permission: the model authors (Convai Innovations, Supersonic
|
|
73
|
+
Labs, Mark Marosi) are named for their models and asked before their
|
|
74
|
+
results are published.
|