typellm 0.3.0.dev2__tar.gz → 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {typellm-0.3.0.dev2/typellm.egg-info → typellm-0.3.1}/PKG-INFO +57 -60
- {typellm-0.3.0.dev2 → typellm-0.3.1}/README.md +56 -59
- {typellm-0.3.0.dev2 → typellm-0.3.1}/pyproject.toml +1 -1
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_batching.py +24 -25
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_concurrency.py +42 -38
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_dependencies.py +18 -18
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_grammar_fields.py +14 -14
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_images.py +17 -17
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_nullable.py +12 -12
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_permutations.py +12 -12
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_prefill.py +18 -30
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_probabilities.py +3 -3
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_prompts.py +5 -14
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_protocols.py +22 -0
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_text.py +18 -21
- {typellm-0.3.0.dev2 → typellm-0.3.1}/tests/test_typellm.py +235 -116
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm/__init__.py +2 -0
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm/cli.py +1 -1
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm/runtime.py +137 -85
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm/schema.py +10 -23
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm/sglang.py +62 -66
- {typellm-0.3.0.dev2 → typellm-0.3.1/typellm.egg-info}/PKG-INFO +57 -60
- {typellm-0.3.0.dev2 → typellm-0.3.1}/LICENSE +0 -0
- {typellm-0.3.0.dev2 → typellm-0.3.1}/setup.cfg +0 -0
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm/__main__.py +0 -0
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm/benchmark.py +0 -0
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm/images.py +0 -0
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm/protocol.py +0 -0
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm.egg-info/SOURCES.txt +0 -0
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm.egg-info/dependency_links.txt +0 -0
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm.egg-info/entry_points.txt +0 -0
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm.egg-info/requires.txt +0 -0
- {typellm-0.3.0.dev2 → typellm-0.3.1}/typellm.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: typellm
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Type-Safe Decoding for Autoregressive LLMs
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://typellm.ai/
|
|
@@ -23,12 +23,14 @@ Dynamic: license-file
|
|
|
23
23
|
<a href="https://typellm.ai/">Homepage</a> •
|
|
24
24
|
<a href="https://typellm.ai/blog">Blog</a> •
|
|
25
25
|
<a href="https://typellm.ai/docs">Docs</a> •
|
|
26
|
-
<a href="https://typellm.ai/
|
|
26
|
+
<a href="https://typellm.ai/examples">Examples</a> •
|
|
27
|
+
<a href="https://typellm.ai/dashboard">API</a> •
|
|
27
28
|
<a href="https://typellm.ai/contact">Contact</a>
|
|
28
29
|
</h4>
|
|
29
30
|
</div>
|
|
30
31
|
|
|
31
32
|
## Updates
|
|
33
|
+
- **[2026/09/29]** The [TypeLLM API](https://typellm.ai) is live: typed outputs without serving a model yourself, and $5 of credit for new accounts. [Get early access](https://typellm.ai/early-access) · [Quick start](#typellm-api-cloud) · [Examples](https://typellm.ai/examples).
|
|
32
34
|
- **[2026/09/24]** Added [image input](#image-input) for vision-language models, tested with Qwen3.8-27B.
|
|
33
35
|
- **[2026/09/23]** Added [JevBench results](https://github.com/TypeLLM/TypeLLM/blob/main/evals/jevbench/README.md): TypeLLM scored 195/231 without thinking and 228/231 with thinking.
|
|
34
36
|
- **[2026/09/23]** Added [permutation averaging](#per-question-permutation-averaging) to improve the predictive distribution. See the [blog post](https://typellm.ai/blog/fair-die).
|
|
@@ -66,37 +68,33 @@ Evaluated on 231 public [JevBench](https://github.com/fstandhartinger/jevbench)
|
|
|
66
68
|
|
|
67
69
|
## Quick start
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
```bash
|
|
72
|
+
pip install -U typellm
|
|
73
|
+
```
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
Call the hosted TypeLLM API, or run TypeLLM against a model you serve yourself.
|
|
76
|
+
Both clients take the same requests.
|
|
73
77
|
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
### TypeLLM API (cloud)
|
|
79
|
+
|
|
80
|
+
[Sign in](https://typellm.ai/login), enter your access code on the
|
|
81
|
+
[API keys](https://typellm.ai/dashboard/keys) page and create a key. No code yet?
|
|
82
|
+
[Get early access](https://typellm.ai/early-access).
|
|
76
83
|
|
|
77
|
-
|
|
84
|
+
```bash
|
|
85
|
+
export TYPELLM_API_KEY="tl-sk-..."
|
|
78
86
|
```
|
|
79
87
|
|
|
80
|
-
|
|
88
|
+
```python
|
|
89
|
+
import os
|
|
90
|
+
from typellm import TypeLLMClient
|
|
81
91
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
A call runs for at most 300 seconds, 60 by default. Set `timeout` on the
|
|
85
|
-
client for a new default, or on `generate()` to override it for one call.
|
|
86
|
-
- Pass `questions`; `schema=`, `cancel` and `print_final_prompt` need your
|
|
87
|
-
own server. Images can be files, bytes, PIL images or data: URIs, not URLs.
|
|
88
|
-
- Each key runs a limited number of calls at once, told with the key. Calls
|
|
89
|
-
beyond it fail right away with HTTP 429.
|
|
90
|
-
- Errors raise `SGLangError` with the HTTP status in `.status`, and a call
|
|
91
|
-
that runs out of time raises `GenerationTimeout`. The service caps the
|
|
92
|
-
context size and the images, answering 400 past them, and stops string
|
|
93
|
-
answers at 128 tokens (`maxLength` is refused).
|
|
94
|
-
- Successful calls set `last_usage` from the service's input and thinking token
|
|
95
|
-
counts. Failed hosted calls may not return usage.
|
|
92
|
+
client = TypeLLMClient(api_key=os.environ["TYPELLM_API_KEY"])
|
|
93
|
+
```
|
|
96
94
|
|
|
97
|
-
|
|
95
|
+
See the [API reference](https://typellm.ai/docs/api) to call it over HTTP instead.
|
|
98
96
|
|
|
99
|
-
###
|
|
97
|
+
### Self-hosted with SGLang
|
|
100
98
|
|
|
101
99
|
Use [SGLang](https://github.com/sgl-project/sglang) to configure and serve a
|
|
102
100
|
compatible autoregressive model on your local GPU server. This example uses
|
|
@@ -106,12 +104,6 @@ to start it with prefix caching enabled.
|
|
|
106
104
|
|
|
107
105
|
See [Supported models](#supported-models) for tested checkpoints and thinking behavior.
|
|
108
106
|
|
|
109
|
-
### 2. Run TypeLLM
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
pip install -U typellm
|
|
113
|
-
```
|
|
114
|
-
|
|
115
107
|
Point `TypeLLMClient` at the SGLang server's HTTP endpoint:
|
|
116
108
|
|
|
117
109
|
```python
|
|
@@ -123,10 +115,12 @@ client = TypeLLMClient(
|
|
|
123
115
|
)
|
|
124
116
|
```
|
|
125
117
|
|
|
126
|
-
|
|
118
|
+
### Make a request
|
|
119
|
+
|
|
120
|
+
With either client:
|
|
127
121
|
|
|
128
122
|
```python
|
|
129
|
-
|
|
123
|
+
response = client.generate(
|
|
130
124
|
context="""
|
|
131
125
|
Receipt from Hilton London
|
|
132
126
|
Total: £324.50
|
|
@@ -158,10 +152,12 @@ result = client.generate(
|
|
|
158
152
|
},
|
|
159
153
|
)
|
|
160
154
|
|
|
161
|
-
print(result)
|
|
155
|
+
print(response.result)
|
|
162
156
|
```
|
|
163
157
|
|
|
164
|
-
|
|
158
|
+
`generate()` returns what the HTTP API does: the typed answers in `.result`, the
|
|
159
|
+
reasoning of each field that thought in `.thinking`, and the call's tokens in
|
|
160
|
+
`.usage`. Example `.result`:
|
|
165
161
|
|
|
166
162
|
```python
|
|
167
163
|
{
|
|
@@ -190,7 +186,7 @@ Enum choices support `string`, `integer`, and `number` types, with at most 24 va
|
|
|
190
186
|
A string without `enum` generates free text:
|
|
191
187
|
|
|
192
188
|
```python
|
|
193
|
-
|
|
189
|
+
response = client.generate(
|
|
194
190
|
context="The train ticket is for a client meeting.",
|
|
195
191
|
questions={
|
|
196
192
|
"summary": {"type": "string", "instructions": "Summarize in one sentence."},
|
|
@@ -199,12 +195,13 @@ result = client.generate(
|
|
|
199
195
|
```
|
|
200
196
|
|
|
201
197
|
Free text stops after 128 tokens. Pass `text_max_tokens=` to the client for
|
|
202
|
-
longer answers,
|
|
198
|
+
longer answers, and ask for the length you want in the field's instructions.
|
|
199
|
+
`maxLength` is not supported.
|
|
203
200
|
|
|
204
201
|
Ask for a numeric answer without enumerating every possible value:
|
|
205
202
|
|
|
206
203
|
```python
|
|
207
|
-
|
|
204
|
+
response = client.generate(
|
|
208
205
|
context="Calculate the requested value accurately.",
|
|
209
206
|
questions={
|
|
210
207
|
"answer": {
|
|
@@ -214,7 +211,7 @@ result = client.generate(
|
|
|
214
211
|
},
|
|
215
212
|
)
|
|
216
213
|
|
|
217
|
-
print(result)
|
|
214
|
+
print(response.result)
|
|
218
215
|
# {"answer": 70.0}
|
|
219
216
|
```
|
|
220
217
|
|
|
@@ -240,7 +237,7 @@ Add `"null"` to the type to allow a missing value. The field returns `None`
|
|
|
240
237
|
when the input has no value for it:
|
|
241
238
|
|
|
242
239
|
```python
|
|
243
|
-
|
|
240
|
+
response = client.generate(
|
|
244
241
|
context="Read the attached receipt.",
|
|
245
242
|
images=["receipt.jpg"],
|
|
246
243
|
questions={
|
|
@@ -266,7 +263,7 @@ Thinking is off by default. Turn it on for the fields that need it; the others
|
|
|
266
263
|
answer at once, and the fields that think reason side by side:
|
|
267
264
|
|
|
268
265
|
```python
|
|
269
|
-
|
|
266
|
+
response = client.generate(context=context, questions={
|
|
270
267
|
"total": {"type": "number"},
|
|
271
268
|
"category": {"type": "string", "enum": ["meal", "travel", "equipment"]},
|
|
272
269
|
"policy_ok": {"type": "boolean", "instructions": "Does it meet the travel policy?",
|
|
@@ -274,13 +271,12 @@ result = client.generate(context=context, questions={
|
|
|
274
271
|
})
|
|
275
272
|
```
|
|
276
273
|
|
|
277
|
-
`thinking_budget` caps a field's reasoning
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
on to the typed answer.
|
|
274
|
+
`thinking_budget` caps a field's reasoning. Without one, a field may reason until
|
|
275
|
+
the model's context is full. When reasoning reaches the budget, TypeLLM closes it
|
|
276
|
+
and moves on to the typed answer.
|
|
281
277
|
|
|
282
|
-
|
|
283
|
-
|
|
278
|
+
`response.thinking` maps each field that thought to its reasoning, and
|
|
279
|
+
`response.usage.thinking_tokens` counts the reasoning tokens.
|
|
284
280
|
|
|
285
281
|
Models with always-on thinking reason on every field; `thinking_budget` applies
|
|
286
282
|
to them too. See [Supported models](#supported-models).
|
|
@@ -291,7 +287,7 @@ Pass images with `images=` alongside the text context. The served model must be
|
|
|
291
287
|
a vision-language model, such as `Qwen/Qwen3.8-27B`.
|
|
292
288
|
|
|
293
289
|
```python
|
|
294
|
-
|
|
290
|
+
response = client.generate(
|
|
295
291
|
context="The customer says this receipt was charged twice.",
|
|
296
292
|
images=["receipt.png"],
|
|
297
293
|
questions={
|
|
@@ -311,7 +307,7 @@ Fields run together by default, and each sees only the original context.
|
|
|
311
307
|
When a field needs earlier results, list them in `depends_on`:
|
|
312
308
|
|
|
313
309
|
```python
|
|
314
|
-
|
|
310
|
+
response = client.generate(
|
|
315
311
|
context="The payments service is returning errors after a deployment.",
|
|
316
312
|
questions={
|
|
317
313
|
"system": {
|
|
@@ -349,7 +345,7 @@ step reuses its parent's cached prompt. Unknown names and cycles raise
|
|
|
349
345
|
Set `return_probabilities` on individual enum or boolean fields:
|
|
350
346
|
|
|
351
347
|
```python
|
|
352
|
-
|
|
348
|
+
response = client.generate(
|
|
353
349
|
context=context,
|
|
354
350
|
questions={
|
|
355
351
|
"expense_type": {
|
|
@@ -401,7 +397,7 @@ For a one-off request, use the convenience function:
|
|
|
401
397
|
```python
|
|
402
398
|
from typellm import run_schema
|
|
403
399
|
|
|
404
|
-
|
|
400
|
+
response = run_schema(
|
|
405
401
|
context=context,
|
|
406
402
|
questions=questions,
|
|
407
403
|
base_url="http://127.0.0.1:30000",
|
|
@@ -414,7 +410,7 @@ result = run_schema(
|
|
|
414
410
|
Add `permutations` to an `enum` question to reduce option-order bias. TypeLLM averages the probabilities and keeps the same return format.
|
|
415
411
|
|
|
416
412
|
```python
|
|
417
|
-
|
|
413
|
+
response = client.generate(
|
|
418
414
|
context="A single roll of a fair die.",
|
|
419
415
|
questions={"roll": {
|
|
420
416
|
"type": "string",
|
|
@@ -441,25 +437,25 @@ support this option.
|
|
|
441
437
|
## Serving
|
|
442
438
|
|
|
443
439
|
One `TypeLLMClient` can be shared by many threads. Each call keeps its own
|
|
444
|
-
prompts and usage, and connections to SGLang are reused.
|
|
440
|
+
prompts and usage, and connections to SGLang or the hosted API are reused.
|
|
445
441
|
|
|
446
442
|
```python
|
|
447
443
|
import threading
|
|
448
444
|
|
|
449
445
|
cancel = threading.Event()
|
|
450
|
-
|
|
446
|
+
response = client.generate(
|
|
451
447
|
context=context,
|
|
452
448
|
questions=questions,
|
|
453
449
|
seed=7, # this call's random choices only
|
|
454
450
|
timeout=30, # seconds for the whole call; raises GenerationTimeout
|
|
455
451
|
cancel=cancel, # set it from another thread; raises GenerationCancelled
|
|
456
452
|
)
|
|
457
|
-
print(
|
|
458
|
-
# Usage(requests=4, prompt_tokens=1830, cached_tokens=1504, completion_tokens=7
|
|
453
|
+
print(response.usage)
|
|
454
|
+
# Usage(input_tokens=410, thinking_tokens=0, requests=4, prompt_tokens=1830, cached_tokens=1504, completion_tokens=7)
|
|
459
455
|
```
|
|
460
456
|
|
|
461
|
-
`
|
|
462
|
-
|
|
457
|
+
`usage` reports the tokens of the call. When a call fails partway, the
|
|
458
|
+
exception's `.usage` holds what it spent. `input_tokens` is what you sent, each part
|
|
463
459
|
counted once: the context, the questions as JSON, and the images. The other
|
|
464
460
|
counts are SGLang's for the call's requests, where every prompt carries the
|
|
465
461
|
shared context. A timeout or cancel stops
|
|
@@ -498,8 +494,9 @@ Other sizes in the Qwen3.5 and Qwen3.8 families are expected to be compatible.
|
|
|
498
494
|
|
|
499
495
|
[Image input](#image-input) has been tested with `Qwen/Qwen3.8-27B`.
|
|
500
496
|
|
|
501
|
-
Use the checkpoint ID as `model=`.
|
|
502
|
-
|
|
497
|
+
Use the checkpoint ID as `model=`. TypeLLM loads the tokenizer from the server's
|
|
498
|
+
paths, then its served model name; if none of those loads locally, set
|
|
499
|
+
`tokenizer=` to the matching Hugging Face ID or local directory.
|
|
503
500
|
The tokenizer must load from standard artifacts without custom model code.
|
|
504
501
|
|
|
505
502
|
## Comparison with Jev-style models
|
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
<a href="https://typellm.ai/">Homepage</a> •
|
|
9
9
|
<a href="https://typellm.ai/blog">Blog</a> •
|
|
10
10
|
<a href="https://typellm.ai/docs">Docs</a> •
|
|
11
|
-
<a href="https://typellm.ai/
|
|
11
|
+
<a href="https://typellm.ai/examples">Examples</a> •
|
|
12
|
+
<a href="https://typellm.ai/dashboard">API</a> •
|
|
12
13
|
<a href="https://typellm.ai/contact">Contact</a>
|
|
13
14
|
</h4>
|
|
14
15
|
</div>
|
|
15
16
|
|
|
16
17
|
## Updates
|
|
18
|
+
- **[2026/09/29]** The [TypeLLM API](https://typellm.ai) is live: typed outputs without serving a model yourself, and $5 of credit for new accounts. [Get early access](https://typellm.ai/early-access) · [Quick start](#typellm-api-cloud) · [Examples](https://typellm.ai/examples).
|
|
17
19
|
- **[2026/09/24]** Added [image input](#image-input) for vision-language models, tested with Qwen3.8-27B.
|
|
18
20
|
- **[2026/09/23]** Added [JevBench results](https://github.com/TypeLLM/TypeLLM/blob/main/evals/jevbench/README.md): TypeLLM scored 195/231 without thinking and 228/231 with thinking.
|
|
19
21
|
- **[2026/09/23]** Added [permutation averaging](#per-question-permutation-averaging) to improve the predictive distribution. See the [blog post](https://typellm.ai/blog/fair-die).
|
|
@@ -51,37 +53,33 @@ Evaluated on 231 public [JevBench](https://github.com/fstandhartinger/jevbench)
|
|
|
51
53
|
|
|
52
54
|
## Quick start
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+
```bash
|
|
57
|
+
pip install -U typellm
|
|
58
|
+
```
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
Call the hosted TypeLLM API, or run TypeLLM against a model you serve yourself.
|
|
61
|
+
Both clients take the same requests.
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
### TypeLLM API (cloud)
|
|
64
|
+
|
|
65
|
+
[Sign in](https://typellm.ai/login), enter your access code on the
|
|
66
|
+
[API keys](https://typellm.ai/dashboard/keys) page and create a key. No code yet?
|
|
67
|
+
[Get early access](https://typellm.ai/early-access).
|
|
61
68
|
|
|
62
|
-
|
|
69
|
+
```bash
|
|
70
|
+
export TYPELLM_API_KEY="tl-sk-..."
|
|
63
71
|
```
|
|
64
72
|
|
|
65
|
-
|
|
73
|
+
```python
|
|
74
|
+
import os
|
|
75
|
+
from typellm import TypeLLMClient
|
|
66
76
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
A call runs for at most 300 seconds, 60 by default. Set `timeout` on the
|
|
70
|
-
client for a new default, or on `generate()` to override it for one call.
|
|
71
|
-
- Pass `questions`; `schema=`, `cancel` and `print_final_prompt` need your
|
|
72
|
-
own server. Images can be files, bytes, PIL images or data: URIs, not URLs.
|
|
73
|
-
- Each key runs a limited number of calls at once, told with the key. Calls
|
|
74
|
-
beyond it fail right away with HTTP 429.
|
|
75
|
-
- Errors raise `SGLangError` with the HTTP status in `.status`, and a call
|
|
76
|
-
that runs out of time raises `GenerationTimeout`. The service caps the
|
|
77
|
-
context size and the images, answering 400 past them, and stops string
|
|
78
|
-
answers at 128 tokens (`maxLength` is refused).
|
|
79
|
-
- Successful calls set `last_usage` from the service's input and thinking token
|
|
80
|
-
counts. Failed hosted calls may not return usage.
|
|
77
|
+
client = TypeLLMClient(api_key=os.environ["TYPELLM_API_KEY"])
|
|
78
|
+
```
|
|
81
79
|
|
|
82
|
-
|
|
80
|
+
See the [API reference](https://typellm.ai/docs/api) to call it over HTTP instead.
|
|
83
81
|
|
|
84
|
-
###
|
|
82
|
+
### Self-hosted with SGLang
|
|
85
83
|
|
|
86
84
|
Use [SGLang](https://github.com/sgl-project/sglang) to configure and serve a
|
|
87
85
|
compatible autoregressive model on your local GPU server. This example uses
|
|
@@ -91,12 +89,6 @@ to start it with prefix caching enabled.
|
|
|
91
89
|
|
|
92
90
|
See [Supported models](#supported-models) for tested checkpoints and thinking behavior.
|
|
93
91
|
|
|
94
|
-
### 2. Run TypeLLM
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
pip install -U typellm
|
|
98
|
-
```
|
|
99
|
-
|
|
100
92
|
Point `TypeLLMClient` at the SGLang server's HTTP endpoint:
|
|
101
93
|
|
|
102
94
|
```python
|
|
@@ -108,10 +100,12 @@ client = TypeLLMClient(
|
|
|
108
100
|
)
|
|
109
101
|
```
|
|
110
102
|
|
|
111
|
-
|
|
103
|
+
### Make a request
|
|
104
|
+
|
|
105
|
+
With either client:
|
|
112
106
|
|
|
113
107
|
```python
|
|
114
|
-
|
|
108
|
+
response = client.generate(
|
|
115
109
|
context="""
|
|
116
110
|
Receipt from Hilton London
|
|
117
111
|
Total: £324.50
|
|
@@ -143,10 +137,12 @@ result = client.generate(
|
|
|
143
137
|
},
|
|
144
138
|
)
|
|
145
139
|
|
|
146
|
-
print(result)
|
|
140
|
+
print(response.result)
|
|
147
141
|
```
|
|
148
142
|
|
|
149
|
-
|
|
143
|
+
`generate()` returns what the HTTP API does: the typed answers in `.result`, the
|
|
144
|
+
reasoning of each field that thought in `.thinking`, and the call's tokens in
|
|
145
|
+
`.usage`. Example `.result`:
|
|
150
146
|
|
|
151
147
|
```python
|
|
152
148
|
{
|
|
@@ -175,7 +171,7 @@ Enum choices support `string`, `integer`, and `number` types, with at most 24 va
|
|
|
175
171
|
A string without `enum` generates free text:
|
|
176
172
|
|
|
177
173
|
```python
|
|
178
|
-
|
|
174
|
+
response = client.generate(
|
|
179
175
|
context="The train ticket is for a client meeting.",
|
|
180
176
|
questions={
|
|
181
177
|
"summary": {"type": "string", "instructions": "Summarize in one sentence."},
|
|
@@ -184,12 +180,13 @@ result = client.generate(
|
|
|
184
180
|
```
|
|
185
181
|
|
|
186
182
|
Free text stops after 128 tokens. Pass `text_max_tokens=` to the client for
|
|
187
|
-
longer answers,
|
|
183
|
+
longer answers, and ask for the length you want in the field's instructions.
|
|
184
|
+
`maxLength` is not supported.
|
|
188
185
|
|
|
189
186
|
Ask for a numeric answer without enumerating every possible value:
|
|
190
187
|
|
|
191
188
|
```python
|
|
192
|
-
|
|
189
|
+
response = client.generate(
|
|
193
190
|
context="Calculate the requested value accurately.",
|
|
194
191
|
questions={
|
|
195
192
|
"answer": {
|
|
@@ -199,7 +196,7 @@ result = client.generate(
|
|
|
199
196
|
},
|
|
200
197
|
)
|
|
201
198
|
|
|
202
|
-
print(result)
|
|
199
|
+
print(response.result)
|
|
203
200
|
# {"answer": 70.0}
|
|
204
201
|
```
|
|
205
202
|
|
|
@@ -225,7 +222,7 @@ Add `"null"` to the type to allow a missing value. The field returns `None`
|
|
|
225
222
|
when the input has no value for it:
|
|
226
223
|
|
|
227
224
|
```python
|
|
228
|
-
|
|
225
|
+
response = client.generate(
|
|
229
226
|
context="Read the attached receipt.",
|
|
230
227
|
images=["receipt.jpg"],
|
|
231
228
|
questions={
|
|
@@ -251,7 +248,7 @@ Thinking is off by default. Turn it on for the fields that need it; the others
|
|
|
251
248
|
answer at once, and the fields that think reason side by side:
|
|
252
249
|
|
|
253
250
|
```python
|
|
254
|
-
|
|
251
|
+
response = client.generate(context=context, questions={
|
|
255
252
|
"total": {"type": "number"},
|
|
256
253
|
"category": {"type": "string", "enum": ["meal", "travel", "equipment"]},
|
|
257
254
|
"policy_ok": {"type": "boolean", "instructions": "Does it meet the travel policy?",
|
|
@@ -259,13 +256,12 @@ result = client.generate(context=context, questions={
|
|
|
259
256
|
})
|
|
260
257
|
```
|
|
261
258
|
|
|
262
|
-
`thinking_budget` caps a field's reasoning
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
on to the typed answer.
|
|
259
|
+
`thinking_budget` caps a field's reasoning. Without one, a field may reason until
|
|
260
|
+
the model's context is full. When reasoning reaches the budget, TypeLLM closes it
|
|
261
|
+
and moves on to the typed answer.
|
|
266
262
|
|
|
267
|
-
|
|
268
|
-
|
|
263
|
+
`response.thinking` maps each field that thought to its reasoning, and
|
|
264
|
+
`response.usage.thinking_tokens` counts the reasoning tokens.
|
|
269
265
|
|
|
270
266
|
Models with always-on thinking reason on every field; `thinking_budget` applies
|
|
271
267
|
to them too. See [Supported models](#supported-models).
|
|
@@ -276,7 +272,7 @@ Pass images with `images=` alongside the text context. The served model must be
|
|
|
276
272
|
a vision-language model, such as `Qwen/Qwen3.8-27B`.
|
|
277
273
|
|
|
278
274
|
```python
|
|
279
|
-
|
|
275
|
+
response = client.generate(
|
|
280
276
|
context="The customer says this receipt was charged twice.",
|
|
281
277
|
images=["receipt.png"],
|
|
282
278
|
questions={
|
|
@@ -296,7 +292,7 @@ Fields run together by default, and each sees only the original context.
|
|
|
296
292
|
When a field needs earlier results, list them in `depends_on`:
|
|
297
293
|
|
|
298
294
|
```python
|
|
299
|
-
|
|
295
|
+
response = client.generate(
|
|
300
296
|
context="The payments service is returning errors after a deployment.",
|
|
301
297
|
questions={
|
|
302
298
|
"system": {
|
|
@@ -334,7 +330,7 @@ step reuses its parent's cached prompt. Unknown names and cycles raise
|
|
|
334
330
|
Set `return_probabilities` on individual enum or boolean fields:
|
|
335
331
|
|
|
336
332
|
```python
|
|
337
|
-
|
|
333
|
+
response = client.generate(
|
|
338
334
|
context=context,
|
|
339
335
|
questions={
|
|
340
336
|
"expense_type": {
|
|
@@ -386,7 +382,7 @@ For a one-off request, use the convenience function:
|
|
|
386
382
|
```python
|
|
387
383
|
from typellm import run_schema
|
|
388
384
|
|
|
389
|
-
|
|
385
|
+
response = run_schema(
|
|
390
386
|
context=context,
|
|
391
387
|
questions=questions,
|
|
392
388
|
base_url="http://127.0.0.1:30000",
|
|
@@ -399,7 +395,7 @@ result = run_schema(
|
|
|
399
395
|
Add `permutations` to an `enum` question to reduce option-order bias. TypeLLM averages the probabilities and keeps the same return format.
|
|
400
396
|
|
|
401
397
|
```python
|
|
402
|
-
|
|
398
|
+
response = client.generate(
|
|
403
399
|
context="A single roll of a fair die.",
|
|
404
400
|
questions={"roll": {
|
|
405
401
|
"type": "string",
|
|
@@ -426,25 +422,25 @@ support this option.
|
|
|
426
422
|
## Serving
|
|
427
423
|
|
|
428
424
|
One `TypeLLMClient` can be shared by many threads. Each call keeps its own
|
|
429
|
-
prompts and usage, and connections to SGLang are reused.
|
|
425
|
+
prompts and usage, and connections to SGLang or the hosted API are reused.
|
|
430
426
|
|
|
431
427
|
```python
|
|
432
428
|
import threading
|
|
433
429
|
|
|
434
430
|
cancel = threading.Event()
|
|
435
|
-
|
|
431
|
+
response = client.generate(
|
|
436
432
|
context=context,
|
|
437
433
|
questions=questions,
|
|
438
434
|
seed=7, # this call's random choices only
|
|
439
435
|
timeout=30, # seconds for the whole call; raises GenerationTimeout
|
|
440
436
|
cancel=cancel, # set it from another thread; raises GenerationCancelled
|
|
441
437
|
)
|
|
442
|
-
print(
|
|
443
|
-
# Usage(requests=4, prompt_tokens=1830, cached_tokens=1504, completion_tokens=7
|
|
438
|
+
print(response.usage)
|
|
439
|
+
# Usage(input_tokens=410, thinking_tokens=0, requests=4, prompt_tokens=1830, cached_tokens=1504, completion_tokens=7)
|
|
444
440
|
```
|
|
445
441
|
|
|
446
|
-
`
|
|
447
|
-
|
|
442
|
+
`usage` reports the tokens of the call. When a call fails partway, the
|
|
443
|
+
exception's `.usage` holds what it spent. `input_tokens` is what you sent, each part
|
|
448
444
|
counted once: the context, the questions as JSON, and the images. The other
|
|
449
445
|
counts are SGLang's for the call's requests, where every prompt carries the
|
|
450
446
|
shared context. A timeout or cancel stops
|
|
@@ -483,8 +479,9 @@ Other sizes in the Qwen3.5 and Qwen3.8 families are expected to be compatible.
|
|
|
483
479
|
|
|
484
480
|
[Image input](#image-input) has been tested with `Qwen/Qwen3.8-27B`.
|
|
485
481
|
|
|
486
|
-
Use the checkpoint ID as `model=`.
|
|
487
|
-
|
|
482
|
+
Use the checkpoint ID as `model=`. TypeLLM loads the tokenizer from the server's
|
|
483
|
+
paths, then its served model name; if none of those loads locally, set
|
|
484
|
+
`tokenizer=` to the matching Hugging Face ID or local directory.
|
|
488
485
|
The tokenizer must load from standard artifacts without custom model code.
|
|
489
486
|
|
|
490
487
|
## Comparison with Jev-style models
|