ommlds 0.0.0.dev467__py3-none-any.whl → 0.0.0.dev469__py3-none-any.whl

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.

Potentially problematic release.


This version of ommlds might be problematic. Click here for more details.

Files changed (36) hide show
  1. ommlds/.omlish-manifests.json +109 -2
  2. ommlds/__about__.py +2 -2
  3. ommlds/_hacks/__init__.py +4 -0
  4. ommlds/_hacks/funcs.py +110 -0
  5. ommlds/_hacks/names.py +158 -0
  6. ommlds/_hacks/params.py +73 -0
  7. ommlds/_hacks/patches.py +0 -3
  8. ommlds/backends/ollama/__init__.py +0 -0
  9. ommlds/backends/ollama/protocol.py +170 -0
  10. ommlds/backends/transformers/__init__.py +0 -0
  11. ommlds/backends/transformers/filecache.py +109 -0
  12. ommlds/backends/transformers/streamers.py +73 -0
  13. ommlds/cli/main.py +11 -5
  14. ommlds/cli/sessions/chat/backends/catalog.py +1 -1
  15. ommlds/cli/sessions/completion/session.py +1 -1
  16. ommlds/cli/sessions/embedding/session.py +1 -1
  17. ommlds/minichain/__init__.py +5 -0
  18. ommlds/minichain/backends/catalogs/base.py +14 -1
  19. ommlds/minichain/backends/catalogs/simple.py +2 -2
  20. ommlds/minichain/backends/catalogs/strings.py +9 -7
  21. ommlds/minichain/backends/impls/anthropic/stream.py +1 -2
  22. ommlds/minichain/backends/impls/google/stream.py +1 -2
  23. ommlds/minichain/backends/impls/llamacpp/chat.py +9 -0
  24. ommlds/minichain/backends/impls/llamacpp/stream.py +26 -10
  25. ommlds/minichain/backends/impls/ollama/__init__.py +0 -0
  26. ommlds/minichain/backends/impls/ollama/chat.py +199 -0
  27. ommlds/minichain/backends/impls/openai/stream.py +1 -2
  28. ommlds/minichain/backends/impls/transformers/transformers.py +134 -17
  29. ommlds/minichain/registries/globals.py +18 -4
  30. ommlds/minichain/standard.py +7 -0
  31. {ommlds-0.0.0.dev467.dist-info → ommlds-0.0.0.dev469.dist-info}/METADATA +7 -7
  32. {ommlds-0.0.0.dev467.dist-info → ommlds-0.0.0.dev469.dist-info}/RECORD +36 -26
  33. {ommlds-0.0.0.dev467.dist-info → ommlds-0.0.0.dev469.dist-info}/WHEEL +0 -0
  34. {ommlds-0.0.0.dev467.dist-info → ommlds-0.0.0.dev469.dist-info}/entry_points.txt +0 -0
  35. {ommlds-0.0.0.dev467.dist-info → ommlds-0.0.0.dev469.dist-info}/licenses/LICENSE +0 -0
  36. {ommlds-0.0.0.dev467.dist-info → ommlds-0.0.0.dev469.dist-info}/top_level.txt +0 -0
@@ -170,6 +170,21 @@
170
170
  "attr": null,
171
171
  "file": "ommlds/minichain/backends/impls/llamacpp/chat.py",
172
172
  "line": 33,
173
+ "value": {
174
+ "!.minichain.backends.strings.manifests.BackendStringsManifest": {
175
+ "service_cls_names": [
176
+ "ChatChoicesService"
177
+ ],
178
+ "backend_name": "llamacpp",
179
+ "model_names": null
180
+ }
181
+ }
182
+ },
183
+ {
184
+ "module": ".minichain.backends.impls.llamacpp.chat",
185
+ "attr": null,
186
+ "file": "ommlds/minichain/backends/impls/llamacpp/chat.py",
187
+ "line": 42,
173
188
  "value": {
174
189
  "!.minichain.registries.manifests.RegistryManifest": {
175
190
  "module": "ommlds.minichain.backends.impls.llamacpp.chat",
@@ -200,6 +215,21 @@
200
215
  "attr": null,
201
216
  "file": "ommlds/minichain/backends/impls/llamacpp/stream.py",
202
217
  "line": 32,
218
+ "value": {
219
+ "!.minichain.backends.strings.manifests.BackendStringsManifest": {
220
+ "service_cls_names": [
221
+ "ChatChoicesStreamService"
222
+ ],
223
+ "backend_name": "llamacpp",
224
+ "model_names": null
225
+ }
226
+ }
227
+ },
228
+ {
229
+ "module": ".minichain.backends.impls.llamacpp.stream",
230
+ "attr": null,
231
+ "file": "ommlds/minichain/backends/impls/llamacpp/stream.py",
232
+ "line": 41,
203
233
  "value": {
204
234
  "!.minichain.registries.manifests.RegistryManifest": {
205
235
  "module": "ommlds.minichain.backends.impls.llamacpp.stream",
@@ -271,6 +301,52 @@
271
301
  }
272
302
  }
273
303
  },
304
+ {
305
+ "module": ".minichain.backends.impls.ollama.chat",
306
+ "attr": null,
307
+ "file": "ommlds/minichain/backends/impls/ollama/chat.py",
308
+ "line": 38,
309
+ "value": {
310
+ "!.minichain.backends.strings.manifests.BackendStringsManifest": {
311
+ "service_cls_names": [
312
+ "ChatChoicesService",
313
+ "ChatChoicesStreamService"
314
+ ],
315
+ "backend_name": "ollama",
316
+ "model_names": null
317
+ }
318
+ }
319
+ },
320
+ {
321
+ "module": ".minichain.backends.impls.ollama.chat",
322
+ "attr": null,
323
+ "file": "ommlds/minichain/backends/impls/ollama/chat.py",
324
+ "line": 96,
325
+ "value": {
326
+ "!.minichain.registries.manifests.RegistryManifest": {
327
+ "module": "ommlds.minichain.backends.impls.ollama.chat",
328
+ "attr": "OllamaChatChoicesService",
329
+ "name": "ollama",
330
+ "aliases": null,
331
+ "type": "ChatChoicesService"
332
+ }
333
+ }
334
+ },
335
+ {
336
+ "module": ".minichain.backends.impls.ollama.chat",
337
+ "attr": null,
338
+ "file": "ommlds/minichain/backends/impls/ollama/chat.py",
339
+ "line": 143,
340
+ "value": {
341
+ "!.minichain.registries.manifests.RegistryManifest": {
342
+ "module": "ommlds.minichain.backends.impls.ollama.chat",
343
+ "attr": "OllamaChatChoicesStreamService",
344
+ "name": "ollama",
345
+ "aliases": null,
346
+ "type": "ChatChoicesStreamService"
347
+ }
348
+ }
349
+ },
274
350
  {
275
351
  "module": ".minichain.backends.impls.openai.chat",
276
352
  "attr": null,
@@ -450,7 +526,23 @@
450
526
  "module": ".minichain.backends.impls.transformers.transformers",
451
527
  "attr": null,
452
528
  "file": "ommlds/minichain/backends/impls/transformers/transformers.py",
453
- "line": 43,
529
+ "line": 50,
530
+ "value": {
531
+ "!.minichain.backends.strings.manifests.BackendStringsManifest": {
532
+ "service_cls_names": [
533
+ "ChatChoicesService",
534
+ "ChatChoicesStreamService"
535
+ ],
536
+ "backend_name": "transformers",
537
+ "model_names": null
538
+ }
539
+ }
540
+ },
541
+ {
542
+ "module": ".minichain.backends.impls.transformers.transformers",
543
+ "attr": null,
544
+ "file": "ommlds/minichain/backends/impls/transformers/transformers.py",
545
+ "line": 66,
454
546
  "value": {
455
547
  "!.minichain.registries.manifests.RegistryManifest": {
456
548
  "module": "ommlds.minichain.backends.impls.transformers.transformers",
@@ -467,7 +559,7 @@
467
559
  "module": ".minichain.backends.impls.transformers.transformers",
468
560
  "attr": null,
469
561
  "file": "ommlds/minichain/backends/impls/transformers/transformers.py",
470
- "line": 131,
562
+ "line": 197,
471
563
  "value": {
472
564
  "!.minichain.registries.manifests.RegistryManifest": {
473
565
  "module": "ommlds.minichain.backends.impls.transformers.transformers",
@@ -480,6 +572,21 @@
480
572
  }
481
573
  }
482
574
  },
575
+ {
576
+ "module": ".minichain.backends.impls.transformers.transformers",
577
+ "attr": null,
578
+ "file": "ommlds/minichain/backends/impls/transformers/transformers.py",
579
+ "line": 227,
580
+ "value": {
581
+ "!.minichain.registries.manifests.RegistryManifest": {
582
+ "module": "ommlds.minichain.backends.impls.transformers.transformers",
583
+ "attr": "TransformersChatChoicesStreamService",
584
+ "name": "transformers",
585
+ "aliases": null,
586
+ "type": "ChatChoicesStreamService"
587
+ }
588
+ }
589
+ },
483
590
  {
484
591
  "module": ".minichain.chat.choices.services",
485
592
  "attr": null,
ommlds/__about__.py CHANGED
@@ -37,8 +37,8 @@ class Project(ProjectBase):
37
37
  ],
38
38
 
39
39
  'huggingface': [
40
- 'huggingface-hub ~= 0.35',
41
- 'datasets ~= 4.2',
40
+ 'huggingface-hub ~= 0.36',
41
+ 'datasets ~= 4.3',
42
42
  ],
43
43
 
44
44
  'numpy': [
ommlds/_hacks/__init__.py CHANGED
@@ -0,0 +1,4 @@
1
+ """
2
+ Currently, and ideally, the only thing this codebase will ever interact with requiring these kinds of awful hacks is ML
3
+ code - thus these 'helpers' are kept here, not in the core library.
4
+ """
ommlds/_hacks/funcs.py ADDED
@@ -0,0 +1,110 @@
1
+ import dataclasses as dc
2
+ import linecache
3
+ import textwrap
4
+ import threading
5
+ import types
6
+ import typing as ta
7
+ import uuid
8
+ import warnings
9
+
10
+ from omlish import check
11
+ from omlish import lang
12
+
13
+ from .names import NamespaceBuilder
14
+ from .params import render_param_spec_call
15
+ from .params import render_param_spec_def
16
+
17
+
18
+ ##
19
+
20
+
21
+ @dc.dataclass()
22
+ class _ReservedFilenameEntry:
23
+ unique_id: str
24
+ seq: int = 0
25
+
26
+
27
+ _RESERVED_FILENAME_UUID_TLS = threading.local()
28
+
29
+
30
+ def reserve_linecache_filename(prefix: str) -> str:
31
+ try:
32
+ e = _RESERVED_FILENAME_UUID_TLS.unique_id
33
+ except AttributeError:
34
+ e = _RESERVED_FILENAME_UUID_TLS.unique_id = _ReservedFilenameEntry(str(uuid.uuid4()))
35
+
36
+ while True:
37
+ unique_filename = f'<generated:{prefix}:{e.seq}>'
38
+ cache_line = (1, None, (e.unique_id,), unique_filename)
39
+ e.seq += 1
40
+ if linecache.cache.setdefault(unique_filename, cache_line) == cache_line: # type: ignore
41
+ return unique_filename
42
+
43
+
44
+ ##
45
+
46
+
47
+ def create_function(
48
+ name: str,
49
+ params: lang.CanParamSpec,
50
+ body: str,
51
+ *,
52
+ globals: ta.Mapping[str, ta.Any] | None = None, # noqa
53
+ locals: ta.Mapping[str, ta.Any] | None = None, # noqa
54
+ indent: str = ' ',
55
+ ) -> types.FunctionType:
56
+ params = lang.ParamSpec.of(params)
57
+ check.isinstance(body, str)
58
+ locals = dict(locals or {}) # noqa
59
+
60
+ nsb = NamespaceBuilder(reserved_names=set(locals) | set(globals or []))
61
+ sig = render_param_spec_def(params, nsb)
62
+ for k, v in nsb.items():
63
+ check.not_in(k, locals)
64
+ locals[k] = v
65
+
66
+ body_txt = '\n'.join([
67
+ f'def {name}{sig}:',
68
+ textwrap.indent(textwrap.dedent(body.strip()), indent),
69
+ ])
70
+
71
+ exec_txt = '\n'.join([
72
+ f'def __create_fn__({", ".join(locals.keys())}):',
73
+ textwrap.indent(body_txt, indent),
74
+ f'{indent}return {name}',
75
+ ])
76
+
77
+ ns: dict = {}
78
+ filename = reserve_linecache_filename(name)
79
+ bytecode = compile(exec_txt, filename, 'exec')
80
+ eval(bytecode, globals or {}, ns) # type: ignore # noqa
81
+
82
+ fn = ns['__create_fn__'](**locals)
83
+ fn.__source__ = body_txt
84
+ linecache.cache[filename] = (len(exec_txt), None, exec_txt.splitlines(True), filename)
85
+ return fn
86
+
87
+
88
+ ##
89
+
90
+
91
+ def create_detour(
92
+ params: lang.CanParamSpec,
93
+ target: ta.Callable,
94
+ *,
95
+ as_kwargs: bool = False,
96
+ ) -> types.CodeType:
97
+ params = lang.ParamSpec.of(params)
98
+ check.callable(target)
99
+
100
+ with warnings.catch_warnings():
101
+ warnings.filterwarnings('ignore', category=SyntaxWarning)
102
+
103
+ gfn = create_function(
104
+ '_',
105
+ params,
106
+ f'return 1{render_param_spec_call(params, as_kwargs=as_kwargs)}',
107
+ )
108
+
109
+ check.state(gfn.__code__.co_consts[:2] == (None, 1))
110
+ return gfn.__code__.replace(co_consts=(None, target, *gfn.__code__.co_consts[2:]))
ommlds/_hacks/names.py ADDED
@@ -0,0 +1,158 @@
1
+ """
2
+ TODO:
3
+ - releaseable names
4
+ """
5
+ import string
6
+ import typing as ta
7
+
8
+ from omlish import check
9
+ from omlish import collections as col
10
+
11
+
12
+ ##
13
+
14
+
15
+ class NameGenerator(ta.Protocol):
16
+ def __call__(self, prefix: str = '') -> str: ...
17
+
18
+
19
+ #
20
+
21
+
22
+ class NameGeneratorImpl:
23
+ DEFAULT_PREFIX: ta.ClassVar[str] = '_'
24
+
25
+ def __init__(
26
+ self,
27
+ *,
28
+ reserved_names: ta.Iterable[str] | None = None,
29
+ global_prefix: str | None = None,
30
+ use_global_prefix_if_present: bool = False,
31
+ add_global_prefix_before_number: bool = False,
32
+ ) -> None:
33
+ super().__init__()
34
+
35
+ check.arg(not isinstance(reserved_names, str))
36
+ self._reserved_names = {check.isinstance(n, str) for n in (reserved_names or [])}
37
+ self._global_prefix = global_prefix if global_prefix is not None else self.DEFAULT_PREFIX
38
+ self._use_global_prefix_if_present = bool(use_global_prefix_if_present)
39
+ self._add_global_prefix_before_number = bool(add_global_prefix_before_number)
40
+
41
+ self._name_counts: dict[str, int] = {}
42
+
43
+ def __call__(self, prefix: str = '') -> str:
44
+ if self._use_global_prefix_if_present and prefix.startswith(self._global_prefix):
45
+ base_name = prefix
46
+ else:
47
+ base_name = self._global_prefix + prefix
48
+
49
+ base_count = -1
50
+ if base_name[-1] in string.digits:
51
+ i = len(base_name) - 2
52
+ while i >= 0 and base_name[i] in string.digits:
53
+ i -= 1
54
+ i += 1
55
+ base_count = int(base_name[i:])
56
+ base_name = base_name[:i]
57
+
58
+ if self._add_global_prefix_before_number:
59
+ if not (self._use_global_prefix_if_present and base_name.endswith(self._global_prefix)):
60
+ base_name += self._global_prefix
61
+
62
+ if base_count >= 0:
63
+ count = self._name_counts.setdefault(base_name, 0)
64
+ if base_count > count:
65
+ self._name_counts[base_name] = base_count
66
+
67
+ while True:
68
+ count = self._name_counts.get(base_name, 0)
69
+ self._name_counts[base_name] = count + 1
70
+ name = base_name + str(count)
71
+ if name not in self._reserved_names:
72
+ return name
73
+
74
+
75
+ name_generator = NameGeneratorImpl
76
+
77
+
78
+ ##
79
+
80
+
81
+ class NamespaceBuilder(ta.Mapping[str, ta.Any]):
82
+ def __init__(
83
+ self,
84
+ *,
85
+ reserved_names: ta.Iterable[str] | None = None,
86
+ name_generator: NameGenerator | None = None, # noqa
87
+ ) -> None:
88
+ super().__init__()
89
+
90
+ self._reserved_names = {
91
+ check.isinstance(n, str)
92
+ for n in (check.not_isinstance(reserved_names, str) or [])
93
+ }
94
+ self._name_generator = check.callable(name_generator) if name_generator is not None else \
95
+ NameGeneratorImpl(reserved_names=self._reserved_names, use_global_prefix_if_present=True)
96
+
97
+ self._dct: ta.MutableMapping[str, ta.Any] = {}
98
+ self._dedupe_dct: ta.MutableMapping[ta.Any, str] = col.IdentityKeyDict()
99
+
100
+ @property
101
+ def reserved_names(self) -> ta.AbstractSet[str]:
102
+ return self._reserved_names
103
+
104
+ @property
105
+ def name_generator(self) -> NameGenerator:
106
+ return self._name_generator
107
+
108
+ def __getitem__(self, k: str) -> ta.Any:
109
+ return self._dct[k]
110
+
111
+ def __len__(self):
112
+ return len(self._dct)
113
+
114
+ def __iter__(self) -> ta.Iterator[str]:
115
+ return iter(self._dct)
116
+
117
+ def items(self) -> ta.ItemsView[str, ta.Any]:
118
+ return self._dct.items()
119
+
120
+ def put(
121
+ self,
122
+ value: ta.Any,
123
+ name: str | None = None,
124
+ *,
125
+ exact: bool = False,
126
+ dedupe: bool = False,
127
+ ) -> str:
128
+ check.arg(not (name is None and exact))
129
+ if name is not None:
130
+ check.isinstance(name, str)
131
+
132
+ if dedupe:
133
+ try:
134
+ return self._dedupe_dct[value]
135
+ except KeyError:
136
+ pass
137
+
138
+ if name is not None:
139
+ if name not in self._reserved_names:
140
+ try:
141
+ existing = self._dct[name]
142
+ except KeyError:
143
+ self._dct[name] = value
144
+ if dedupe:
145
+ self._dedupe_dct[value] = name
146
+ return name
147
+ else:
148
+ if existing is value:
149
+ return name
150
+ if exact:
151
+ raise KeyError(name)
152
+
153
+ gen_name = self._name_generator(name or '')
154
+ check.not_in(gen_name, self._dct)
155
+ self._dct[gen_name] = value
156
+ if dedupe:
157
+ self._dedupe_dct[value] = gen_name
158
+ return gen_name
@@ -0,0 +1,73 @@
1
+ import typing as ta
2
+
3
+ from omlish import lang
4
+
5
+ from .names import NamespaceBuilder
6
+
7
+
8
+ ##
9
+
10
+
11
+ def render_param_spec_call(
12
+ params: lang.ParamSpec,
13
+ *,
14
+ as_kwargs: bool = False,
15
+ ) -> str:
16
+ src = ['(']
17
+
18
+ for i, p in enumerate(params):
19
+ if isinstance(p, lang.ParamSeparator):
20
+ continue
21
+
22
+ if i:
23
+ src.append(', ')
24
+
25
+ if as_kwargs:
26
+ if isinstance(p, lang.Param):
27
+ src.append(f'{p.name}={p.name}')
28
+ else:
29
+ raise TypeError(p)
30
+
31
+ else:
32
+ if isinstance(p, lang.ArgsParam):
33
+ src.append(f'*{p.name}')
34
+ elif isinstance(p, lang.KwargsParam):
35
+ src.append(f'**{p.name}')
36
+ elif isinstance(p, lang.PosOnlyParam):
37
+ src.append(p.name)
38
+ elif isinstance(p, lang.KwOnlyParam):
39
+ src.append(f'{p.name}={p.name}')
40
+ elif isinstance(p, lang.ValParam):
41
+ src.append(p.name)
42
+ else:
43
+ raise TypeError(p)
44
+
45
+ src.append(')')
46
+
47
+ return ''.join(src)
48
+
49
+
50
+ def render_param_spec_def(
51
+ params: lang.ParamSpec,
52
+ nsb: NamespaceBuilder,
53
+ *,
54
+ return_ann: lang.Maybe[ta.Any] = lang.empty(),
55
+ ) -> str:
56
+ src = ['(']
57
+
58
+ for i, p in enumerate(params):
59
+ if i:
60
+ src.append(', ')
61
+
62
+ src.append(lang.param_render(
63
+ p,
64
+ render_annotation=lambda ann: nsb.put(ann, f'ann_{p.name}'), # noqa
65
+ render_default=lambda dfl: nsb.put(dfl, f'dfl_{p.name}'), # noqa
66
+ ))
67
+
68
+ src.append(')')
69
+
70
+ if return_ann.present:
71
+ src.append(f' -> {nsb.put(return_ann.must(), "ann_return")}')
72
+
73
+ return ''.join(src)
ommlds/_hacks/patches.py CHANGED
@@ -1,7 +1,4 @@
1
1
  """
2
- Currently, and ideally, the only thing this codebase will ever interact with requiring these kinds of awful hacks is ML
3
- code - thus these 'helpers' are kept here, not in the core library.
4
-
5
2
  TODO:
6
3
  - patch lock
7
4
  - thread / context local gating
File without changes
@@ -0,0 +1,170 @@
1
+ """
2
+ https://docs.ollama.com/api
3
+ """
4
+ import typing as ta
5
+
6
+ from omlish import dataclasses as dc
7
+ from omlish import lang
8
+
9
+
10
+ ##
11
+
12
+
13
+ @dc.dataclass(frozen=True, kw_only=True)
14
+ @dc.extra_class_params(default_repr_fn=dc.opt_repr)
15
+ class Options:
16
+ # loading
17
+ numa: bool | None = None
18
+ num_ctx: int | None = None
19
+ num_batch: int | None = None
20
+ num_gpu: int | None = None
21
+ main_gpu: int | None = None
22
+ low_vram: bool | None = None
23
+ f16_kv: bool | None = None
24
+ logits_all: bool | None = None
25
+ vocab_only: bool | None = None
26
+ use_mmap: bool | None = None
27
+ use_mlock: bool | None = None
28
+ embedding_only: bool | None = None
29
+ num_thread: int | None = None
30
+
31
+ # querying
32
+ num_keep: int | None = None
33
+ seed: int | None = None
34
+ num_predict: int | None = None
35
+ top_k: int | None = None
36
+ top_p: float | None = None
37
+ tfs_z: float | None = None
38
+ typical_p: float | None = None
39
+ repeat_last_n: int | None = None
40
+ temperature: float | None = None
41
+ repeat_penalty: float | None = None
42
+ presence_penalty: float | None = None
43
+ frequency_penalty: float | None = None
44
+ mirostat: int | None = None
45
+ mirostat_tau: float | None = None
46
+ mirostat_eta: float | None = None
47
+ penalize_newline: bool | None = None
48
+ stop: ta.Sequence[str] | None = None
49
+
50
+
51
+ ##
52
+
53
+
54
+ @dc.dataclass(frozen=True, kw_only=True)
55
+ class BaseRequest(lang.Abstract):
56
+ model: str
57
+
58
+
59
+ @dc.dataclass(frozen=True, kw_only=True)
60
+ class BaseStreamableRequest(BaseRequest, lang.Abstract):
61
+ stream: bool | None = None
62
+
63
+
64
+ ##
65
+
66
+
67
+ @dc.dataclass(frozen=True, kw_only=True)
68
+ class BaseGenerateRequest(BaseStreamableRequest, lang.Abstract):
69
+ options: Options | None = None
70
+ format: ta.Literal['', 'json'] | None = None # TODO: jsonschema
71
+ keep_alive: float | str | None = None
72
+
73
+
74
+ @dc.dataclass(frozen=True, kw_only=True)
75
+ @dc.extra_class_params(default_repr_fn=dc.opt_repr)
76
+ class GenerateRequest(BaseGenerateRequest):
77
+ prompt: str | None = None
78
+ suffix: str | None = None
79
+ system: str | None = None
80
+ template: str | None = None
81
+ context: ta.Sequence[int] | None = None
82
+ raw: bool | None = None
83
+ images: ta.Sequence[bytes] | None = None
84
+ think: bool | ta.Literal['low', 'medium', 'high'] | None = None
85
+
86
+
87
+ #
88
+
89
+
90
+ @dc.dataclass(frozen=True, kw_only=True)
91
+ class BaseGenerateResponse(lang.Abstract):
92
+ model: str | None = None
93
+ created_at: str | None = None
94
+ done: bool | None = None
95
+ done_reason: str | None = None
96
+ total_duration: int | None = None
97
+ load_duration: int | None = None
98
+ prompt_eval_count: int | None = None
99
+ prompt_eval_duration: int | None = None
100
+ eval_count: int | None = None
101
+ eval_duration: int | None = None
102
+
103
+
104
+ @dc.dataclass(frozen=True, kw_only=True)
105
+ @dc.extra_class_params(default_repr_fn=dc.opt_repr)
106
+ class GenerateResponse(BaseGenerateResponse):
107
+ response: str
108
+ thinking: str | None = None
109
+ context: ta.Sequence[int] | None = None
110
+
111
+
112
+ ##
113
+
114
+
115
+ Role: ta.TypeAlias = ta.Literal[
116
+ 'system',
117
+ 'user',
118
+ 'assistant',
119
+ 'tool',
120
+ ]
121
+
122
+
123
+ @dc.dataclass(frozen=True, kw_only=True)
124
+ @dc.extra_class_params(default_repr_fn=dc.opt_repr)
125
+ class Message:
126
+ role: Role
127
+ content: str | None = None
128
+ thinking: str | None = None
129
+ images: ta.Sequence[bytes] | None = None
130
+ tool_name: str | None = None
131
+
132
+ @dc.dataclass(frozen=True, kw_only=True)
133
+ class ToolCall:
134
+ @dc.dataclass(frozen=True, kw_only=True)
135
+ class Function:
136
+ name: str
137
+ arguments: ta.Mapping[str, ta.Any]
138
+
139
+ function: Function
140
+
141
+ tool_calls: ta.Sequence[ToolCall] | None = None
142
+
143
+
144
+ @dc.dataclass(frozen=True, kw_only=True)
145
+ @dc.extra_class_params(default_repr_fn=dc.opt_repr)
146
+ class Tool:
147
+ type: str | None = 'function'
148
+
149
+ @dc.dataclass(frozen=True, kw_only=True)
150
+ @dc.extra_class_params(default_repr_fn=dc.opt_repr)
151
+ class Function:
152
+ name: str | None = None
153
+ description: str | None = None
154
+ parameters: ta.Any | None = None
155
+
156
+ function: Function | None = None
157
+
158
+
159
+ @dc.dataclass(frozen=True, kw_only=True)
160
+ @dc.extra_class_params(default_repr_fn=dc.opt_repr)
161
+ class ChatRequest(BaseGenerateRequest):
162
+ messages: ta.Sequence[Message] | None = None
163
+ tools: ta.Sequence[Tool] | None = None
164
+ think: bool | ta.Literal['low', 'medium', 'high'] | None = None
165
+
166
+
167
+ @dc.dataclass(frozen=True, kw_only=True)
168
+ @dc.extra_class_params(default_repr_fn=dc.opt_repr)
169
+ class ChatResponse(BaseGenerateResponse):
170
+ message: Message
File without changes