open-cricket 0.1.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.
- open_cricket-0.1.0/LICENSE +21 -0
- open_cricket-0.1.0/MANIFEST.in +4 -0
- open_cricket-0.1.0/PKG-INFO +353 -0
- open_cricket-0.1.0/README.md +322 -0
- open_cricket-0.1.0/docs/README.md +44 -0
- open_cricket-0.1.0/docs/api.md +155 -0
- open_cricket-0.1.0/docs/assets/open-cricket-icon.svg +11 -0
- open_cricket-0.1.0/docs/jev-migration.md +170 -0
- open_cricket-0.1.0/docs/renaming.md +28 -0
- open_cricket-0.1.0/docs/sdk.md +163 -0
- open_cricket-0.1.0/docs/server.md +98 -0
- open_cricket-0.1.0/docs/technical/README.md +16 -0
- open_cricket-0.1.0/docs/technical/architecture.md +95 -0
- open_cricket-0.1.0/docs/technical/backends.md +90 -0
- open_cricket-0.1.0/docs/technical/contributing.md +89 -0
- open_cricket-0.1.0/docs/technical/releases.md +64 -0
- open_cricket-0.1.0/docs/technical/scoring.md +99 -0
- open_cricket-0.1.0/examples/benchmark_backend.py +86 -0
- open_cricket-0.1.0/examples/demo-result.json +20 -0
- open_cricket-0.1.0/examples/langchain_chat.py +31 -0
- open_cricket-0.1.0/examples/langgraph_workflow.py +48 -0
- open_cricket-0.1.0/examples/support.json +24 -0
- open_cricket-0.1.0/open_cricket/__init__.py +6 -0
- open_cricket-0.1.0/open_cricket/backend.py +34 -0
- open_cricket-0.1.0/open_cricket/cli.py +132 -0
- open_cricket-0.1.0/open_cricket/client.py +38 -0
- open_cricket-0.1.0/open_cricket/core.py +122 -0
- open_cricket-0.1.0/open_cricket/hf.py +71 -0
- open_cricket-0.1.0/open_cricket/integrations.py +182 -0
- open_cricket-0.1.0/open_cricket/local.py +87 -0
- open_cricket-0.1.0/open_cricket/mlx.py +49 -0
- open_cricket-0.1.0/open_cricket/questionnaire.py +94 -0
- open_cricket-0.1.0/open_cricket/sdk.py +35 -0
- open_cricket-0.1.0/open_cricket/server.py +88 -0
- open_cricket-0.1.0/open_cricket/systemone.py +199 -0
- open_cricket-0.1.0/open_cricket.egg-info/PKG-INFO +353 -0
- open_cricket-0.1.0/open_cricket.egg-info/SOURCES.txt +50 -0
- open_cricket-0.1.0/open_cricket.egg-info/dependency_links.txt +1 -0
- open_cricket-0.1.0/open_cricket.egg-info/entry_points.txt +2 -0
- open_cricket-0.1.0/open_cricket.egg-info/requires.txt +29 -0
- open_cricket-0.1.0/open_cricket.egg-info/top_level.txt +1 -0
- open_cricket-0.1.0/pyproject.toml +27 -0
- open_cricket-0.1.0/setup.cfg +4 -0
- open_cricket-0.1.0/tests/test_cli.py +125 -0
- open_cricket-0.1.0/tests/test_client.py +35 -0
- open_cricket-0.1.0/tests/test_core.py +104 -0
- open_cricket-0.1.0/tests/test_integrations.py +122 -0
- open_cricket-0.1.0/tests/test_local.py +124 -0
- open_cricket-0.1.0/tests/test_sdk.py +99 -0
- open_cricket-0.1.0/tests/test_server.py +14 -0
- open_cricket-0.1.0/tests/test_systemone.py +235 -0
- open_cricket-0.1.0/uv.lock +2561 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jonathan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: open-cricket
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Questionnaire classification using causal-LM token probabilities
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: pydantic<3,>=2.9
|
|
10
|
+
Provides-Extra: hf
|
|
11
|
+
Requires-Dist: torch<3,>=2.2; extra == "hf"
|
|
12
|
+
Requires-Dist: transformers<5,>=4.45; extra == "hf"
|
|
13
|
+
Provides-Extra: mlx
|
|
14
|
+
Requires-Dist: mlx-lm<0.29,>=0.28; (sys_platform == "darwin" and platform_machine == "arm64") and extra == "mlx"
|
|
15
|
+
Provides-Extra: langchain
|
|
16
|
+
Requires-Dist: langchain-core<2,>=1; extra == "langchain"
|
|
17
|
+
Provides-Extra: langgraph
|
|
18
|
+
Requires-Dist: langchain-core<2,>=1; extra == "langgraph"
|
|
19
|
+
Requires-Dist: langgraph<2,>=1; extra == "langgraph"
|
|
20
|
+
Provides-Extra: server
|
|
21
|
+
Requires-Dist: langchain-core<2,>=1; extra == "server"
|
|
22
|
+
Requires-Dist: fastapi<1,>=0.115; extra == "server"
|
|
23
|
+
Requires-Dist: uvicorn<1,>=0.30; extra == "server"
|
|
24
|
+
Provides-Extra: test
|
|
25
|
+
Requires-Dist: langchain-core<2,>=1; extra == "test"
|
|
26
|
+
Requires-Dist: langgraph<2,>=1; extra == "test"
|
|
27
|
+
Requires-Dist: fastapi<1,>=0.115; extra == "test"
|
|
28
|
+
Requires-Dist: httpx<1,>=0.27; extra == "test"
|
|
29
|
+
Requires-Dist: typesafe-sdk<0.8,>=0.7; extra == "test"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# Open Cricket
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
Local structured decisions using causal language models. The CLI, Python SDK,
|
|
37
|
+
REST API, and LangChain integrations share one request contract:
|
|
38
|
+
**`state`, `model`, and a map of typed `questions`**. Responses contain `model`,
|
|
39
|
+
`answers`, and `usage`. Choice selects a category, Score evaluates a rubric,
|
|
40
|
+
and Noul returns the relative probability of a yes/true answer.
|
|
41
|
+
|
|
42
|
+
The default checkpoint is `Qwen/Qwen2.5-1.5B-Instruct`. Open Cricket is independent
|
|
43
|
+
of TypeSafe; its API follows Jev's general call shapes, but model predictions
|
|
44
|
+
and confidence calibration differ.
|
|
45
|
+
|
|
46
|
+
## Documentation
|
|
47
|
+
|
|
48
|
+
See the [documentation index](docs/README.md) for the [server guide](docs/server.md),
|
|
49
|
+
[API reference](docs/api.md), and [Python SDK guide](docs/sdk.md).
|
|
50
|
+
The [technical section](docs/technical/README.md) covers architecture, scoring,
|
|
51
|
+
backend development, and testing for contributors.
|
|
52
|
+
|
|
53
|
+
The package and command are `open-cricket`; Python imports use `open_cricket`.
|
|
54
|
+
See the [rename guide](docs/renaming.md) for configuration changes and the
|
|
55
|
+
[release guide](docs/technical/releases.md) for GitHub-to-PyPI setup.
|
|
56
|
+
|
|
57
|
+
## Quick start: local model, no server
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
uv sync --extra hf
|
|
61
|
+
uv run open-cricket --input examples/support.json --pretty --time
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The same input file can be sent to the REST API or passed to `LocalClient.invoke`.
|
|
65
|
+
For example:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"state": "I was charged twice. Please refund the extra payment.",
|
|
70
|
+
"model": "Qwen/Qwen2.5-1.5B-Instruct",
|
|
71
|
+
"questions": {
|
|
72
|
+
"route": {
|
|
73
|
+
"type": "choice",
|
|
74
|
+
"instructions": "Which team should handle this?",
|
|
75
|
+
"criteria": {
|
|
76
|
+
"billing": "Payments, invoices, and refunds",
|
|
77
|
+
"technical": "Product errors and troubleshooting",
|
|
78
|
+
"other": null
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`examples/support.json` demonstrates Choice, Score, and Noul questions about
|
|
86
|
+
department routing, urgency, and incorrect charges.
|
|
87
|
+
Descriptions belong in `criteria`; use null for a label needing no description.
|
|
88
|
+
State, instructions, and descriptions also accept structured JSON objects and arrays.
|
|
89
|
+
|
|
90
|
+
CLI output defaults to JSON. `--pretty` renders answers and probabilities;
|
|
91
|
+
`--time` reports request time excluding model initialization. The file's `model`
|
|
92
|
+
selects the checkpoint; `--model` overrides it explicitly. `--backend hf|mlx`,
|
|
93
|
+
`--device`, `--revision`, `--mode`, and `--temperature` configure local inference.
|
|
94
|
+
|
|
95
|
+
The first run downloads the selected model from Hugging Face. Remote model code
|
|
96
|
+
is disabled. To explore the scoring mathematics with synthetic probabilities:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
uv run open-cricket --demo --pretty
|
|
100
|
+
uv run open-cricket --demo --mode constrained
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Direct Python SDK
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
import json
|
|
107
|
+
from open_cricket import LocalClient, Choice, Score, Noul
|
|
108
|
+
|
|
109
|
+
client = LocalClient(model="Qwen/Qwen2.5-1.5B-Instruct")
|
|
110
|
+
result = client.system_one(
|
|
111
|
+
state="I was charged twice. Please fix this today.",
|
|
112
|
+
questions={
|
|
113
|
+
"route": Choice(instructions="Which team?", criteria={"billing": "Payments", "other": None}),
|
|
114
|
+
"urgency": Score(criteria=["Can wait", "Within a few days", "Today"]),
|
|
115
|
+
"billing": Noul(instructions="Does this concern billing?"),
|
|
116
|
+
},
|
|
117
|
+
)
|
|
118
|
+
print(result["answers"]["route"]["choice"])
|
|
119
|
+
print(result["answers"]["urgency"]["score"])
|
|
120
|
+
print(result["answers"]["billing"]["noul"])
|
|
121
|
+
|
|
122
|
+
with open("examples/support.json") as f:
|
|
123
|
+
result = client.invoke(json.load(f))
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`LocalClient` keeps the model loaded and serializes access to it. `await
|
|
127
|
+
client.ainvoke(payload)` runs inference in a worker thread. Use `runtime="mlx"`
|
|
128
|
+
for Apple silicon. `backend=...` accepts a custom token backend. The requested
|
|
129
|
+
model must match the client's loaded model. There are no branded model aliases.
|
|
130
|
+
|
|
131
|
+
## REST API and HTTP SDK
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
uv sync --extra hf --extra server
|
|
135
|
+
export OPEN_CRICKET_MODEL=Qwen/Qwen2.5-1.5B-Instruct
|
|
136
|
+
export OPEN_CRICKET_API_KEY="choose-a-local-server-key"
|
|
137
|
+
uv run uvicorn open_cricket.server:app --host 127.0.0.1 --port 8000
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
curl http://127.0.0.1:8000/v1/systemone \
|
|
142
|
+
-H "Authorization: Bearer $OPEN_CRICKET_API_KEY" \
|
|
143
|
+
-H "Content-Type: application/json" \
|
|
144
|
+
--data-binary @examples/support.json
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`GET /v1/models` lists the configured checkpoint. `GET /health` reports readiness;
|
|
148
|
+
`/docs` exposes OpenAPI documentation. Set `OPEN_CRICKET_BACKEND=mlx` to serve MLX.
|
|
149
|
+
Authentication is disabled if `OPEN_CRICKET_API_KEY` is unset. Requests select the
|
|
150
|
+
configured model by its exact name; they do not trigger model downloads.
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
import json
|
|
154
|
+
from open_cricket import Client, Choice
|
|
155
|
+
|
|
156
|
+
client = Client("http://127.0.0.1:8000", api_key="choose-a-local-server-key")
|
|
157
|
+
result = client.system_one(
|
|
158
|
+
state="I was charged twice.",
|
|
159
|
+
questions={"route": Choice(criteria={"billing": None, "other": None})},
|
|
160
|
+
)
|
|
161
|
+
with open("examples/support.json") as f:
|
|
162
|
+
result = client.invoke(json.load(f))
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The HTTP and local SDKs return dictionaries with the same answer shape.
|
|
166
|
+
The server accepts an injected typed runnable through
|
|
167
|
+
`create_app(classifier, model_name="your-checkpoint")`.
|
|
168
|
+
|
|
169
|
+
## LangChain and LangGraph
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
uv sync --extra hf --extra langgraph
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
import json
|
|
177
|
+
from open_cricket.hf import HuggingFaceBackend
|
|
178
|
+
from open_cricket.integrations import as_runnable
|
|
179
|
+
|
|
180
|
+
judge = as_runnable(HuggingFaceBackend(), model="Qwen/Qwen2.5-1.5B-Instruct")
|
|
181
|
+
with open("examples/support.json") as f:
|
|
182
|
+
payload = json.load(f)
|
|
183
|
+
result = judge.invoke(payload)
|
|
184
|
+
results = judge.batch([payload, payload])
|
|
185
|
+
route = judge | (lambda result: result["answers"]["department"]["choice"])
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`ainvoke`, `abatch`, and `Client.as_runnable()` use this same contract.
|
|
189
|
+
`graph_node(judge)` reads `state`, `model`, and `questions` from graph state and
|
|
190
|
+
writes the answer envelope to `classification`, preserving unrelated graph data.
|
|
191
|
+
See `examples/langgraph_workflow.py` for conditional routing.
|
|
192
|
+
|
|
193
|
+
`chat_runnable(chat_model, model_name="provider-model")` also accepts the same
|
|
194
|
+
contract. It scores single-token answer codes and requires all requested code
|
|
195
|
+
probabilities in provider metadata. Missing probabilities raise an error. It has
|
|
196
|
+
a maximum of 26 categories, further limited by `top_logprobs`. See
|
|
197
|
+
`examples/langchain_chat.py`; that example calls a paid provider when run.
|
|
198
|
+
|
|
199
|
+
## Switching from Jev
|
|
200
|
+
|
|
201
|
+
Use the same state/question structure and `system_one` call pattern with your
|
|
202
|
+
local checkpoint name. The [migration guide](docs/jev-migration.md) covers
|
|
203
|
+
existing TypeSafe client configuration and the differences in model behavior,
|
|
204
|
+
confidence, and token accounting.
|
|
205
|
+
|
|
206
|
+
## Faster local inference and Apple silicon
|
|
207
|
+
|
|
208
|
+
Local classification reuses a request-local attention (KV) cache across answer
|
|
209
|
+
prefixes. Branch changes trim ordinary KV caches back to their shared prefix;
|
|
210
|
+
unsupported sliding-window or recurrent cache formats safely recompute instead.
|
|
211
|
+
Hugging Face models that support `logits_to_keep` also compute only the final
|
|
212
|
+
position's vocabulary logits. No labels or answer tokens are skipped, and
|
|
213
|
+
normalisation still uses the full vocabulary. `model_calls` counts scored trie
|
|
214
|
+
nodes, so it does not decrease even though each call does much less work.
|
|
215
|
+
Custom backends implementing the original three-method protocol still work.
|
|
216
|
+
For Hugging Face cache acceleration, use Transformers 4.57; older supported
|
|
217
|
+
versions can fall back to full-prefix scoring.
|
|
218
|
+
|
|
219
|
+
For Apple silicon, install and select the optional MLX runtime:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
uv sync --extra mlx
|
|
223
|
+
uv run open-cricket --backend mlx --input examples/support.json --pretty --time
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
MLX accepts compatible Hugging Face checkpoints and MLX-converted quantized
|
|
227
|
+
checkpoints via `--model`. The selected checkpoint determines weight precision;
|
|
228
|
+
quantization and lower precision can change probabilities and close rankings.
|
|
229
|
+
The MLX extra is restricted to Apple silicon macOS and uses MLX-LM 0.28.x to
|
|
230
|
+
remain compatible with this project's Transformers 4.x dependency. It requires
|
|
231
|
+
an accessible Metal GPU. Hugging Face remains the default runtime.
|
|
232
|
+
|
|
233
|
+
In Python, use `from open_cricket.mlx import MLXBackend` and pass `MLXBackend()`
|
|
234
|
+
to `classify` or `as_runnable`. For the HTTP service:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
uv sync --extra mlx --extra server
|
|
238
|
+
OPEN_CRICKET_BACKEND=mlx uv run uvicorn open_cricket.server:app --host 127.0.0.1
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Keep the model loaded between requests (for example through the HTTP service).
|
|
242
|
+
Starting the CLI for every message reloads the model. The existing runnable
|
|
243
|
+
serializes access to its model; async requests do not provide GPU batching.
|
|
244
|
+
Caches are isolated per classification and are not retained across requests.
|
|
245
|
+
|
|
246
|
+
### Measured performance
|
|
247
|
+
|
|
248
|
+
A local Qwen2.5-0.5B-Instruct benchmark with four options, 112 prompt tokens and
|
|
249
|
+
11 scored prefixes produced these warmed median request times, excluding load:
|
|
250
|
+
|
|
251
|
+
| Runtime | Full-prefix baseline | Optimized | Speedup | Repeats |
|
|
252
|
+
| --- | ---: | ---: | ---: | ---: |
|
|
253
|
+
| Hugging Face, CPU, float32 | 1.350 s | 0.259 s | 5.2× | 5 |
|
|
254
|
+
| MLX, Metal, checkpoint precision | 0.169 s | 0.057 s | 3.0× | 3 |
|
|
255
|
+
|
|
256
|
+
These measurements use the 0.5B checkpoint; they do not measure the new 1.5B
|
|
257
|
+
default. The benchmark script keeps 0.5B as its default for reproducibility.
|
|
258
|
+
These are one local workload, not a general performance guarantee or a comparison
|
|
259
|
+
of MLX against Hugging Face MPS. The largest absolute probability difference
|
|
260
|
+
between baseline and optimized scoring was 0.0000033 for HF and 0.024 for MLX
|
|
261
|
+
(about 2.4 percentage points). MLX's lower-precision model arithmetic can vary
|
|
262
|
+
between full-sequence and incremental evaluation. Float32 miniature-model
|
|
263
|
+
regression tests verify both runtimes' branch rollback against uncached scoring
|
|
264
|
+
to five decimal places. Evaluate your categories before switching runtime or
|
|
265
|
+
weight precision.
|
|
266
|
+
|
|
267
|
+
Reproduce the benchmark with:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
uv run python examples/benchmark_backend.py --device cpu --repeats 5
|
|
271
|
+
uv run python examples/benchmark_backend.py --backend mlx --repeats 5
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
The benchmark alternates cached and uncached runs after warmup and reports both
|
|
275
|
+
speed and probability differences. Rust has not been introduced: eliminating
|
|
276
|
+
repeated model computation provides the demonstrated gain, while rewriting the
|
|
277
|
+
small Python trie would leave that model work unchanged.
|
|
278
|
+
|
|
279
|
+
## What happens mathematically?
|
|
280
|
+
|
|
281
|
+
The questionnaire renders message data as a quoted JSON string, followed by the
|
|
282
|
+
question, allowed options, and `Answer:`. The HF adapter uses the tokenizer's
|
|
283
|
+
chat template and assistant-generation boundary where available. The system
|
|
284
|
+
instruction asks for one JSON-quoted option and immediate end of turn.
|
|
285
|
+
|
|
286
|
+
For an option with token sequence `t1 ... tn EOS`:
|
|
287
|
+
|
|
288
|
+
```text
|
|
289
|
+
score(option) = sum_j log P(tj | questionnaire, t1 ... t(j-1))
|
|
290
|
+
P(option | supplied candidates) = softmax(score(option) / temperature)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Logits become log probabilities using full-vocabulary `log_softmax`. We add
|
|
294
|
+
log probabilities, not probabilities, and do not softmax already normalised
|
|
295
|
+
probabilities. Labels share a token trie: common prefixes are evaluated once
|
|
296
|
+
per question. Every branch is explored; this is not greedy token generation.
|
|
297
|
+
An explicit EOS/end-of-turn token distinguishes a complete answer from a label
|
|
298
|
+
that merely begins the same way. JSON quoting handles multiword labels and
|
|
299
|
+
embedded quotes. Every output is one of the supplied labels by construction.
|
|
300
|
+
|
|
301
|
+
The exact path scores **one canonical tokenisation** of each JSON answer plus
|
|
302
|
+
one tokenizer-defined EOS token, starting at a fixed prompt token boundary.
|
|
303
|
+
It does not sum alternative tokenisations, whitespace, synonyms, or other
|
|
304
|
+
valid end-of-turn tokens. Thus "exact" refers to these particular token-sequence
|
|
305
|
+
events, not all text representations of the underlying category.
|
|
306
|
+
|
|
307
|
+
`mode="constrained"` instead renormalises at every trie branch. It implements
|
|
308
|
+
locally masked generation. This is mathematically different from conditioning
|
|
309
|
+
the original model on the complete candidate set and can change the winner.
|
|
310
|
+
The default is `sequence`. Final temperature acts on completed scores in both
|
|
311
|
+
modes. No length normalisation is used: longer spellings may be penalised.
|
|
312
|
+
Code scoring reduces spelling-length effects but introduces code/order bias.
|
|
313
|
+
|
|
314
|
+
The synthetic demo makes the distinction testable:
|
|
315
|
+
|
|
316
|
+
| Option | Original joint probability | Sequence mode | Constrained mode |
|
|
317
|
+
|---|---:|---:|---:|
|
|
318
|
+
| refund | .06 | .105263 | .074074 |
|
|
319
|
+
| refund status | .24 | .421053 | .592593 |
|
|
320
|
+
| technical | .27 | .473684 | .333333 |
|
|
321
|
+
|
|
322
|
+
## Limits and verification
|
|
323
|
+
|
|
324
|
+
Probabilities are relative to the supplied categories, even if none fits well.
|
|
325
|
+
Include an `other` category when appropriate. Confidence is 1 minus normalized
|
|
326
|
+
Shannon entropy; it is not a calibrated probability of correctness. Score is the
|
|
327
|
+
probability-weighted rubric index; Noul returns the relative probability of true.
|
|
328
|
+
Question wording, label spelling, and model precision can affect the result.
|
|
329
|
+
|
|
330
|
+
Local context limits come from the checkpoint. Requests evaluate each question
|
|
331
|
+
independently and sequentially. Input usage sums prompt lengths across questions;
|
|
332
|
+
local scoring generates no output text, so output usage is zero. An injected
|
|
333
|
+
classifier may report null input usage when no count is available.
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
uv sync --extra test
|
|
337
|
+
uv run python -m unittest discover -s tests -v
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Tests cover scoring mathematics, cache isolation, typed requests and responses,
|
|
341
|
+
CLI validation, local/HTTP SDKs, official TypeSafe SDK interoperability,
|
|
342
|
+
LangChain/LangGraph, authentication, and schema validation. Optional runtime tests
|
|
343
|
+
require their respective HF or MLX dependencies and hardware.
|
|
344
|
+
|
|
345
|
+
## Sources
|
|
346
|
+
|
|
347
|
+
- [TypeSafe's Jev announcement](https://typesafe.ai/blog/introducing-system-one-models-and-jev): describes its architecture, parallel sampler and RLCD training.
|
|
348
|
+
- [Hugging Face model outputs](https://huggingface.co/docs/transformers/main_classes/output): causal-LM logits.
|
|
349
|
+
- [Qwen demonstration model](https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct): loading and chat-template usage.
|
|
350
|
+
- [LangChain ChatOpenAI](https://docs.langchain.com/oss/python/integrations/chat/openai): chat interface and logprobs metadata.
|
|
351
|
+
- [LangGraph graph API](https://docs.langchain.com/oss/python/langgraph/graph-api): state updates and conditional edges.
|
|
352
|
+
|
|
353
|
+
Version 0.1.0. An independent educational prototype; no affiliation with TypeSafe.
|