typellm 0.3.0.dev1__tar.gz → 0.3.0.dev2__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.dev1/typellm.egg-info → typellm-0.3.0.dev2}/PKG-INFO +7 -6
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/README.md +6 -5
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/pyproject.toml +1 -1
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_concurrency.py +32 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_grammar_fields.py +1 -1
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_permutations.py +1 -1
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_typellm.py +27 -1
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm/cli.py +3 -2
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm/runtime.py +41 -14
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm/sglang.py +33 -20
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2/typellm.egg-info}/PKG-INFO +7 -6
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/LICENSE +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/setup.cfg +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_batching.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_dependencies.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_images.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_nullable.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_prefill.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_probabilities.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_prompts.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_protocols.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/tests/test_text.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm/__init__.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm/__main__.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm/benchmark.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm/images.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm/protocol.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm/schema.py +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm.egg-info/SOURCES.txt +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm.egg-info/dependency_links.txt +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm.egg-info/entry_points.txt +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/typellm.egg-info/requires.txt +0 -0
- {typellm-0.3.0.dev1 → typellm-0.3.0.dev2}/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.0.
|
|
3
|
+
Version: 0.3.0.dev2
|
|
4
4
|
Summary: Type-Safe Decoding for Autoregressive LLMs
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://typellm.ai/
|
|
@@ -79,8 +79,8 @@ client = TypeLLMClient(api_key="YOUR_API_KEY") # calls https://api.typellm.ai
|
|
|
79
79
|
|
|
80
80
|
`generate()` then works as in the example below, with these differences:
|
|
81
81
|
|
|
82
|
-
- The service compiles and runs the schema. Use `model`, `
|
|
83
|
-
|
|
82
|
+
- The service compiles and runs the schema. Use `model`, `temperature`, `seed`
|
|
83
|
+
and `timeout`; local compilation settings do not apply.
|
|
84
84
|
A call runs for at most 300 seconds, 60 by default. Set `timeout` on the
|
|
85
85
|
client for a new default, or on `generate()` to override it for one call.
|
|
86
86
|
- Pass `questions`; `schema=`, `cancel` and `print_final_prompt` need your
|
|
@@ -377,19 +377,20 @@ result = client.generate(
|
|
|
377
377
|
Only opted-in fields return `value` and `probabilities`; other fields return plain values.
|
|
378
378
|
The option is not supported on open Numeric or Text fields.
|
|
379
379
|
|
|
380
|
-
|
|
380
|
+
`temperature` is 0 by default: each field gets its most likely answer. Above 0,
|
|
381
|
+
TypeLLM samples at that temperature:
|
|
381
382
|
|
|
382
383
|
```python
|
|
383
384
|
client = TypeLLMClient(
|
|
384
385
|
"http://127.0.0.1:30000",
|
|
385
|
-
mode="sample",
|
|
386
386
|
temperature=0.8,
|
|
387
387
|
seed=42,
|
|
388
388
|
)
|
|
389
389
|
```
|
|
390
390
|
|
|
391
391
|
Sampling applies to finite candidates for Choice fields and to token generation
|
|
392
|
-
for Numeric and Text fields. `temperature`
|
|
392
|
+
for Numeric and Text fields. `generate(temperature=...)` sets it for one call.
|
|
393
|
+
The older `mode="argmax"` / `mode="sample"` still works for now but is deprecated.
|
|
393
394
|
|
|
394
395
|
A seed fixes TypeLLM's own random choices. SGLang's log probabilities can shift
|
|
395
396
|
with its prefix cache and batching, so the same seed may still give different
|
|
@@ -64,8 +64,8 @@ client = TypeLLMClient(api_key="YOUR_API_KEY") # calls https://api.typellm.ai
|
|
|
64
64
|
|
|
65
65
|
`generate()` then works as in the example below, with these differences:
|
|
66
66
|
|
|
67
|
-
- The service compiles and runs the schema. Use `model`, `
|
|
68
|
-
|
|
67
|
+
- The service compiles and runs the schema. Use `model`, `temperature`, `seed`
|
|
68
|
+
and `timeout`; local compilation settings do not apply.
|
|
69
69
|
A call runs for at most 300 seconds, 60 by default. Set `timeout` on the
|
|
70
70
|
client for a new default, or on `generate()` to override it for one call.
|
|
71
71
|
- Pass `questions`; `schema=`, `cancel` and `print_final_prompt` need your
|
|
@@ -362,19 +362,20 @@ result = client.generate(
|
|
|
362
362
|
Only opted-in fields return `value` and `probabilities`; other fields return plain values.
|
|
363
363
|
The option is not supported on open Numeric or Text fields.
|
|
364
364
|
|
|
365
|
-
|
|
365
|
+
`temperature` is 0 by default: each field gets its most likely answer. Above 0,
|
|
366
|
+
TypeLLM samples at that temperature:
|
|
366
367
|
|
|
367
368
|
```python
|
|
368
369
|
client = TypeLLMClient(
|
|
369
370
|
"http://127.0.0.1:30000",
|
|
370
|
-
mode="sample",
|
|
371
371
|
temperature=0.8,
|
|
372
372
|
seed=42,
|
|
373
373
|
)
|
|
374
374
|
```
|
|
375
375
|
|
|
376
376
|
Sampling applies to finite candidates for Choice fields and to token generation
|
|
377
|
-
for Numeric and Text fields. `temperature`
|
|
377
|
+
for Numeric and Text fields. `generate(temperature=...)` sets it for one call.
|
|
378
|
+
The older `mode="argmax"` / `mode="sample"` still works for now but is deprecated.
|
|
378
379
|
|
|
379
380
|
A seed fixes TypeLLM's own random choices. SGLang's log probabilities can shift
|
|
380
381
|
with its prefix cache and batching, so the same seed may still give different
|
|
@@ -212,6 +212,38 @@ class DeadlineTests(unittest.TestCase):
|
|
|
212
212
|
client._generate({"text": "x"})
|
|
213
213
|
self.assertNotIsInstance(caught.exception, GenerationTimeout)
|
|
214
214
|
|
|
215
|
+
def dropping(self, error, times):
|
|
216
|
+
"""A client whose server drops the first `times` requests with `error`."""
|
|
217
|
+
seen = []
|
|
218
|
+
|
|
219
|
+
def handler(request):
|
|
220
|
+
seen.append(request)
|
|
221
|
+
if len(seen) <= times:
|
|
222
|
+
raise error("connection dropped", request=request)
|
|
223
|
+
return httpx.Response(200, json={"text": "ok"})
|
|
224
|
+
|
|
225
|
+
client = SGLangClient()
|
|
226
|
+
client._http_client = httpx.Client(transport=httpx.MockTransport(handler))
|
|
227
|
+
return client, seen
|
|
228
|
+
|
|
229
|
+
def test_a_dropped_connection_is_retried_once(self):
|
|
230
|
+
for error in (httpx.ReadError, httpx.RemoteProtocolError, httpx.WriteError):
|
|
231
|
+
client, seen = self.dropping(error, 1)
|
|
232
|
+
with self.subTest(error=error.__name__):
|
|
233
|
+
self.assertEqual(client._request("/generate", {"text": "x"}), {"text": "ok"})
|
|
234
|
+
self.assertEqual(len(seen), 2)
|
|
235
|
+
client, seen = self.dropping(httpx.ReadError, 2)
|
|
236
|
+
with self.assertRaisesRegex(SGLangError, "Could not reach"):
|
|
237
|
+
client._request("/generate", {"text": "x"})
|
|
238
|
+
self.assertEqual(len(seen), 2)
|
|
239
|
+
|
|
240
|
+
def test_a_refused_connection_is_not_retried(self):
|
|
241
|
+
for error in (httpx.ConnectError, httpx.ReadTimeout):
|
|
242
|
+
client, seen = self.dropping(error, 1)
|
|
243
|
+
with self.subTest(error=error.__name__), self.assertRaises(SGLangError):
|
|
244
|
+
client._request("/generate", {"text": "x"})
|
|
245
|
+
self.assertEqual(len(seen), 1)
|
|
246
|
+
|
|
215
247
|
def test_invalid_budgets_are_rejected(self):
|
|
216
248
|
class Recording(FakeServer):
|
|
217
249
|
def _request(self, path, payload=None, *, allow_text=False):
|
|
@@ -87,7 +87,7 @@ class GrammarNumberTests(unittest.TestCase):
|
|
|
87
87
|
self.assertIn("null", patterns[3])
|
|
88
88
|
|
|
89
89
|
def test_sampling_passes_the_temperature_and_no_truncation(self):
|
|
90
|
-
client = TypeLLMClient(model="fake",
|
|
90
|
+
client = TypeLLMClient(model="fake", temperature=0.7, seed=1)
|
|
91
91
|
client.sglang = FakeServer()
|
|
92
92
|
client.generate(context="Receipt", questions={"a": {"type": "integer"}})
|
|
93
93
|
[params] = regex_requests(client.sglang)[0]["sampling_params"]
|
|
@@ -39,7 +39,7 @@ class PermutationTests(unittest.TestCase):
|
|
|
39
39
|
|
|
40
40
|
def test_sampling_uses_averaged_distribution(self):
|
|
41
41
|
with patch('typellm.runtime._sample', return_value='B') as sample:
|
|
42
|
-
_client, result = self.run_case(False, ['one', 'two', 'three'],
|
|
42
|
+
_client, result = self.run_case(False, ['one', 'two', 'three'], temperature=.5)
|
|
43
43
|
self.assertEqual(result['roll']['value'], 'two')
|
|
44
44
|
self.assertEqual(sample.call_count, 2) # one final choice plus the boolean
|
|
45
45
|
for p in sample.call_args_list[0].args[0].values():
|
|
@@ -956,7 +956,7 @@ class HostedApiTests(unittest.TestCase):
|
|
|
956
956
|
|
|
957
957
|
self.client(handler, temperature=0).generate(
|
|
958
958
|
context="x", questions={"a": {"type": "boolean"}})
|
|
959
|
-
self.client(handler,
|
|
959
|
+
self.client(handler, temperature=0.7).generate(
|
|
960
960
|
context="x", questions={"a": {"type": "boolean"}})
|
|
961
961
|
|
|
962
962
|
self.assertNotIn("temperature", bodies[0]["options"])
|
|
@@ -1025,3 +1025,29 @@ class HostedApiTests(unittest.TestCase):
|
|
|
1025
1025
|
|
|
1026
1026
|
if __name__ == "__main__":
|
|
1027
1027
|
unittest.main()
|
|
1028
|
+
|
|
1029
|
+
|
|
1030
|
+
class DecodingTests(unittest.TestCase):
|
|
1031
|
+
def test_temperature_alone_decides(self):
|
|
1032
|
+
from typellm.runtime import _resolve_decoding
|
|
1033
|
+
|
|
1034
|
+
self.assertEqual(_resolve_decoding(None, None), ("argmax", 0.0))
|
|
1035
|
+
self.assertEqual(_resolve_decoding(None, 0), ("argmax", 0.0))
|
|
1036
|
+
self.assertEqual(_resolve_decoding(None, 0.7), ("sample", 0.7))
|
|
1037
|
+
for bad in (-1, float("nan"), True, "1"):
|
|
1038
|
+
with self.assertRaises(ValueError):
|
|
1039
|
+
_resolve_decoding(None, bad)
|
|
1040
|
+
|
|
1041
|
+
def test_deprecated_mode_still_works(self):
|
|
1042
|
+
from typellm.runtime import _resolve_decoding
|
|
1043
|
+
|
|
1044
|
+
with self.assertWarns(DeprecationWarning):
|
|
1045
|
+
self.assertEqual(_resolve_decoding("sample", None), ("sample", 1.0))
|
|
1046
|
+
with self.assertWarns(DeprecationWarning):
|
|
1047
|
+
self.assertEqual(_resolve_decoding("argmax", 0.7)[0], "argmax")
|
|
1048
|
+
with self.assertWarns(DeprecationWarning), self.assertRaises(ValueError):
|
|
1049
|
+
_resolve_decoding("sample", 0)
|
|
1050
|
+
|
|
1051
|
+
def test_call_temperature_overrides_client(self):
|
|
1052
|
+
client = TypeLLMClient(model="fake", temperature=0.7)
|
|
1053
|
+
self.assertEqual((client.mode, client.temperature), ("sample", 0.7))
|
|
@@ -51,8 +51,9 @@ def main() -> None:
|
|
|
51
51
|
default=os.environ.get("TYPELLM_TOKENIZER"),
|
|
52
52
|
help="Tokenizer path or Hugging Face ID; normally discovered from SGLang",
|
|
53
53
|
)
|
|
54
|
-
parser.add_argument("--
|
|
55
|
-
|
|
54
|
+
parser.add_argument("--temperature", type=float, default=0.0,
|
|
55
|
+
help="0 picks the most likely answer; above 0 samples")
|
|
56
|
+
parser.add_argument("--mode", choices=("argmax", "sample"), help="deprecated; use --temperature")
|
|
56
57
|
parser.add_argument("--numeric-max-digits", type=int, default=32)
|
|
57
58
|
parser.add_argument("--seed", type=int, default=0)
|
|
58
59
|
parser.add_argument("--probabilities", action="store_true")
|
|
@@ -8,6 +8,7 @@ import math
|
|
|
8
8
|
import os
|
|
9
9
|
import random
|
|
10
10
|
import threading
|
|
11
|
+
import warnings
|
|
11
12
|
from contextlib import nullcontext
|
|
12
13
|
from contextvars import ContextVar
|
|
13
14
|
from dataclasses import dataclass, replace
|
|
@@ -154,8 +155,8 @@ class TypeLLMClient:
|
|
|
154
155
|
model: str | None = None,
|
|
155
156
|
*,
|
|
156
157
|
api_key: str | None = None,
|
|
157
|
-
mode: str =
|
|
158
|
-
temperature: float =
|
|
158
|
+
mode: str | None = None,
|
|
159
|
+
temperature: float | None = None,
|
|
159
160
|
seed: int | None = None,
|
|
160
161
|
timeout: float | None = None,
|
|
161
162
|
label_pool: Sequence[str] | None = None,
|
|
@@ -168,11 +169,14 @@ class TypeLLMClient:
|
|
|
168
169
|
|
|
169
170
|
With api_key, calls go to the hosted API instead, by default
|
|
170
171
|
https://api.typellm.ai. It compiles and runs the schema itself. Model
|
|
171
|
-
chooses one of its models;
|
|
172
|
+
chooses one of its models; temperature, seed and timeout apply.
|
|
172
173
|
A hosted timeout set here is the default for generate() calls; without
|
|
173
174
|
one, the service uses its own default.
|
|
175
|
+
|
|
176
|
+
temperature 0 (the default) picks the most likely answer; above 0 samples
|
|
177
|
+
at that temperature. mode is deprecated: temperature alone decides.
|
|
174
178
|
"""
|
|
175
|
-
|
|
179
|
+
mode, temperature = _resolve_decoding(mode, temperature)
|
|
176
180
|
if type(numeric_max_digits) is not int or numeric_max_digits <= 0:
|
|
177
181
|
raise ValueError("numeric_max_digits must be a positive integer")
|
|
178
182
|
self.api_key = api_key
|
|
@@ -412,9 +416,13 @@ class TypeLLMClient:
|
|
|
412
416
|
if not isinstance(questions, Mapping):
|
|
413
417
|
raise SchemaError("questions must be a mapping of field names to definitions")
|
|
414
418
|
schema = {"type": "object", "properties": questions}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
419
|
+
if mode is None and temperature is None:
|
|
420
|
+
active_mode, active_temperature = self.mode, self.temperature
|
|
421
|
+
else:
|
|
422
|
+
# A call's own temperature decides for it, whatever the client's mode.
|
|
423
|
+
if temperature is None:
|
|
424
|
+
temperature = self.temperature or None
|
|
425
|
+
active_mode, active_temperature = _resolve_decoding(mode, temperature)
|
|
418
426
|
if self.api_key is not None:
|
|
419
427
|
if questions is None or cancel is not None or print_final_prompt:
|
|
420
428
|
raise ValueError("with api_key, generate() takes questions; schema, cancel and "
|
|
@@ -546,11 +554,30 @@ def _sample(probs: Mapping[str, float], rng: random.Random) -> str:
|
|
|
546
554
|
return last
|
|
547
555
|
|
|
548
556
|
|
|
549
|
-
def
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
557
|
+
def _resolve_decoding(mode: str | None, temperature: float | None) -> tuple[str, float]:
|
|
558
|
+
"""The (mode, temperature) that temperature, and the deprecated mode, ask for.
|
|
559
|
+
|
|
560
|
+
temperature 0 picks the most likely answer (argmax); above 0 samples. For
|
|
561
|
+
older code, mode="sample" without a temperature samples at 1.0 and
|
|
562
|
+
mode="argmax" is argmax whatever the temperature.
|
|
563
|
+
"""
|
|
564
|
+
if mode is not None:
|
|
565
|
+
warnings.warn("mode is deprecated; temperature 0 picks the most likely answer and "
|
|
566
|
+
"above 0 samples", DeprecationWarning, stacklevel=3)
|
|
567
|
+
if mode not in {"argmax", "sample"}:
|
|
568
|
+
raise ValueError("mode must be 'argmax' or 'sample'")
|
|
569
|
+
if mode == "sample" and temperature is None:
|
|
570
|
+
temperature = 1.0
|
|
571
|
+
if temperature is None:
|
|
572
|
+
temperature = 0.0
|
|
573
|
+
if (isinstance(temperature, bool) or not isinstance(temperature, (int, float))
|
|
574
|
+
or not math.isfinite(temperature) or temperature < 0):
|
|
575
|
+
raise ValueError("temperature must be a finite number >= 0")
|
|
576
|
+
if mode == "argmax":
|
|
577
|
+
return "argmax", float(temperature)
|
|
578
|
+
if mode == "sample" and temperature == 0:
|
|
579
|
+
raise ValueError("temperature must be > 0 in sample mode")
|
|
580
|
+
return ("sample" if temperature > 0 else "argmax"), float(temperature)
|
|
554
581
|
|
|
555
582
|
|
|
556
583
|
def _numeric_text_is_complete(text: str, numeric_type: str) -> bool:
|
|
@@ -1006,8 +1033,8 @@ def _print_final_prompts(prefixes: Sequence[str]) -> None:
|
|
|
1006
1033
|
def run_schema(
|
|
1007
1034
|
context: str | None = None,
|
|
1008
1035
|
schema: Mapping[str, Any] | None = None,
|
|
1009
|
-
mode: str =
|
|
1010
|
-
temperature: float =
|
|
1036
|
+
mode: str | None = None,
|
|
1037
|
+
temperature: float | None = None,
|
|
1011
1038
|
*,
|
|
1012
1039
|
state: str | None = None,
|
|
1013
1040
|
questions: Mapping[str, Any] | None = None,
|
|
@@ -252,9 +252,11 @@ class SGLangClient:
|
|
|
252
252
|
def _http(self) -> httpx.Client:
|
|
253
253
|
with self._load_lock:
|
|
254
254
|
if self._http_client is None:
|
|
255
|
-
# Keep-alive connections: one call makes many small requests.
|
|
255
|
+
# Keep-alive connections: one call makes many small requests. Idle
|
|
256
|
+
# ones are dropped before SGLang closes them (5 s), so a request
|
|
257
|
+
# rarely goes out on a connection the server has just closed.
|
|
256
258
|
self._http_client = httpx.Client(limits=httpx.Limits(
|
|
257
|
-
max_connections=None, max_keepalive_connections=64,
|
|
259
|
+
max_connections=None, max_keepalive_connections=64, keepalive_expiry=2.0,
|
|
258
260
|
))
|
|
259
261
|
return self._http_client
|
|
260
262
|
|
|
@@ -269,24 +271,15 @@ class SGLangClient:
|
|
|
269
271
|
scope = _call_scope.get()
|
|
270
272
|
timeout = self.timeout if scope is None else scope.socket_timeout(self.timeout)
|
|
271
273
|
try:
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
try:
|
|
282
|
-
detail = response.read().decode("utf-8", errors="replace")
|
|
283
|
-
except httpx.HTTPError as read_error:
|
|
284
|
-
detail = f"Could not read error response: {read_error}"
|
|
285
|
-
raise SGLangError(
|
|
286
|
-
f"SGLang {path} returned HTTP {response.status_code}: {detail}",
|
|
287
|
-
status=response.status_code,
|
|
288
|
-
)
|
|
289
|
-
raw = response.read().decode("utf-8")
|
|
274
|
+
try:
|
|
275
|
+
raw = self._send(path, payload is None, body, timeout)
|
|
276
|
+
except (httpx.ReadError, httpx.WriteError, httpx.RemoteProtocolError):
|
|
277
|
+
# The connection dropped before an answer, most often a pooled one
|
|
278
|
+
# the server had just closed. SGLang is fine: try once on a new one.
|
|
279
|
+
if scope is not None:
|
|
280
|
+
scope.check()
|
|
281
|
+
timeout = scope.socket_timeout(self.timeout)
|
|
282
|
+
raw = self._send(path, payload is None, body, timeout)
|
|
290
283
|
except httpx.HTTPError as exc:
|
|
291
284
|
# Connection failures, timeouts, resets and truncated responses.
|
|
292
285
|
raise SGLangError(
|
|
@@ -301,6 +294,26 @@ class SGLangClient:
|
|
|
301
294
|
f"SGLang {path} returned non-JSON data: {raw[:500]}"
|
|
302
295
|
) from exc
|
|
303
296
|
|
|
297
|
+
def _send(self, path: str, get: bool, body: bytes | None, timeout: float) -> str:
|
|
298
|
+
# Streamed so a failed body read still reports the status it follows.
|
|
299
|
+
with self._http().stream(
|
|
300
|
+
"GET" if get else "POST",
|
|
301
|
+
self.base_url + path,
|
|
302
|
+
content=body,
|
|
303
|
+
headers={"Content-Type": "application/json"},
|
|
304
|
+
timeout=timeout,
|
|
305
|
+
) as response:
|
|
306
|
+
if response.status_code >= 400:
|
|
307
|
+
try:
|
|
308
|
+
detail = response.read().decode("utf-8", errors="replace")
|
|
309
|
+
except httpx.HTTPError as read_error:
|
|
310
|
+
detail = f"Could not read error response: {read_error}"
|
|
311
|
+
raise SGLangError(
|
|
312
|
+
f"SGLang {path} returned HTTP {response.status_code}: {detail}",
|
|
313
|
+
status=response.status_code,
|
|
314
|
+
)
|
|
315
|
+
return response.read().decode("utf-8")
|
|
316
|
+
|
|
304
317
|
@contextmanager
|
|
305
318
|
def images(self, images: Sequence[str]) -> Iterator[None]:
|
|
306
319
|
"""Attach encoded images to every /generate request made in this block."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: typellm
|
|
3
|
-
Version: 0.3.0.
|
|
3
|
+
Version: 0.3.0.dev2
|
|
4
4
|
Summary: Type-Safe Decoding for Autoregressive LLMs
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://typellm.ai/
|
|
@@ -79,8 +79,8 @@ client = TypeLLMClient(api_key="YOUR_API_KEY") # calls https://api.typellm.ai
|
|
|
79
79
|
|
|
80
80
|
`generate()` then works as in the example below, with these differences:
|
|
81
81
|
|
|
82
|
-
- The service compiles and runs the schema. Use `model`, `
|
|
83
|
-
|
|
82
|
+
- The service compiles and runs the schema. Use `model`, `temperature`, `seed`
|
|
83
|
+
and `timeout`; local compilation settings do not apply.
|
|
84
84
|
A call runs for at most 300 seconds, 60 by default. Set `timeout` on the
|
|
85
85
|
client for a new default, or on `generate()` to override it for one call.
|
|
86
86
|
- Pass `questions`; `schema=`, `cancel` and `print_final_prompt` need your
|
|
@@ -377,19 +377,20 @@ result = client.generate(
|
|
|
377
377
|
Only opted-in fields return `value` and `probabilities`; other fields return plain values.
|
|
378
378
|
The option is not supported on open Numeric or Text fields.
|
|
379
379
|
|
|
380
|
-
|
|
380
|
+
`temperature` is 0 by default: each field gets its most likely answer. Above 0,
|
|
381
|
+
TypeLLM samples at that temperature:
|
|
381
382
|
|
|
382
383
|
```python
|
|
383
384
|
client = TypeLLMClient(
|
|
384
385
|
"http://127.0.0.1:30000",
|
|
385
|
-
mode="sample",
|
|
386
386
|
temperature=0.8,
|
|
387
387
|
seed=42,
|
|
388
388
|
)
|
|
389
389
|
```
|
|
390
390
|
|
|
391
391
|
Sampling applies to finite candidates for Choice fields and to token generation
|
|
392
|
-
for Numeric and Text fields. `temperature`
|
|
392
|
+
for Numeric and Text fields. `generate(temperature=...)` sets it for one call.
|
|
393
|
+
The older `mode="argmax"` / `mode="sample"` still works for now but is deprecated.
|
|
393
394
|
|
|
394
395
|
A seed fixes TypeLLM's own random choices. SGLang's log probabilities can shift
|
|
395
396
|
with its prefix cache and batching, so the same seed may still give different
|
|
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
|