ommlds 0.0.0.dev468__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.

@@ -321,7 +321,7 @@
321
321
  "module": ".minichain.backends.impls.ollama.chat",
322
322
  "attr": null,
323
323
  "file": "ommlds/minichain/backends/impls/ollama/chat.py",
324
- "line": 93,
324
+ "line": 96,
325
325
  "value": {
326
326
  "!.minichain.registries.manifests.RegistryManifest": {
327
327
  "module": "ommlds.minichain.backends.impls.ollama.chat",
@@ -336,7 +336,7 @@
336
336
  "module": ".minichain.backends.impls.ollama.chat",
337
337
  "attr": null,
338
338
  "file": "ommlds/minichain/backends/impls/ollama/chat.py",
339
- "line": 139,
339
+ "line": 143,
340
340
  "value": {
341
341
  "!.minichain.registries.manifests.RegistryManifest": {
342
342
  "module": "ommlds.minichain.backends.impls.ollama.chat",
@@ -526,7 +526,7 @@
526
526
  "module": ".minichain.backends.impls.transformers.transformers",
527
527
  "attr": null,
528
528
  "file": "ommlds/minichain/backends/impls/transformers/transformers.py",
529
- "line": 46,
529
+ "line": 50,
530
530
  "value": {
531
531
  "!.minichain.backends.strings.manifests.BackendStringsManifest": {
532
532
  "service_cls_names": [
@@ -542,7 +542,7 @@
542
542
  "module": ".minichain.backends.impls.transformers.transformers",
543
543
  "attr": null,
544
544
  "file": "ommlds/minichain/backends/impls/transformers/transformers.py",
545
- "line": 62,
545
+ "line": 66,
546
546
  "value": {
547
547
  "!.minichain.registries.manifests.RegistryManifest": {
548
548
  "module": "ommlds.minichain.backends.impls.transformers.transformers",
@@ -559,7 +559,7 @@
559
559
  "module": ".minichain.backends.impls.transformers.transformers",
560
560
  "attr": null,
561
561
  "file": "ommlds/minichain/backends/impls/transformers/transformers.py",
562
- "line": 189,
562
+ "line": 197,
563
563
  "value": {
564
564
  "!.minichain.registries.manifests.RegistryManifest": {
565
565
  "module": "ommlds.minichain.backends.impls.transformers.transformers",
@@ -576,7 +576,7 @@
576
576
  "module": ".minichain.backends.impls.transformers.transformers",
577
577
  "attr": null,
578
578
  "file": "ommlds/minichain/backends/impls/transformers/transformers.py",
579
- "line": 219,
579
+ "line": 227,
580
580
  "value": {
581
581
  "!.minichain.registries.manifests.RegistryManifest": {
582
582
  "module": "ommlds.minichain.backends.impls.transformers.transformers",
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
@@ -0,0 +1,109 @@
1
+ import contextlib
2
+ import dataclasses as dc
3
+ import os
4
+ import threading
5
+ import typing as ta
6
+
7
+ import transformers as tfm
8
+
9
+ from omlish import lang
10
+
11
+ from ..._hacks.funcs import create_detour
12
+
13
+
14
+ ##
15
+
16
+
17
+ @dc.dataclass(frozen=True, kw_only=True)
18
+ class _FileCachePatchContext:
19
+ local_first: bool = False
20
+ local_config_present_is_authoritative: bool = False
21
+
22
+
23
+ _FILE_CACHE_PATCH_CONTEXT_TLS = threading.local()
24
+
25
+
26
+ def _get_file_cache_patch_context() -> _FileCachePatchContext:
27
+ try:
28
+ return _FILE_CACHE_PATCH_CONTEXT_TLS.context
29
+ except AttributeError:
30
+ ctx = _FILE_CACHE_PATCH_CONTEXT_TLS.context = _FileCachePatchContext()
31
+ return ctx
32
+
33
+
34
+ _FILE_CACHE_PATCH_LOCK = threading.Lock()
35
+
36
+
37
+ @lang.cached_function(lock=_FILE_CACHE_PATCH_LOCK)
38
+ def patch_file_cache() -> None:
39
+ """
40
+ I tried to make a `local_first_pipeline` function to be called instead of `tfm.pipeline`, I really did, but the
41
+ transformers code is such a disgusting rat's nest full of direct static calls to the caching code strewn about at
42
+ every layer with no concern whatsoever for forwarding kwargs where they need to go.
43
+ """
44
+
45
+ from transformers.utils.hub import cached_files
46
+
47
+ orig_cached_files: ta.Callable[..., str | None] = lang.copy_function(cached_files) # type: ignore
48
+
49
+ get_file_cache_patch_context = _get_file_cache_patch_context
50
+
51
+ def new_cached_files(
52
+ path_or_repo_id: str | os.PathLike,
53
+ filenames: list[str],
54
+ **kwargs: ta.Any,
55
+ ) -> str | None:
56
+ ctx = get_file_cache_patch_context()
57
+
58
+ if ctx.local_first and not kwargs.get('local_files_only'):
59
+ try:
60
+ local = orig_cached_files(
61
+ path_or_repo_id,
62
+ filenames,
63
+ **{**kwargs, 'local_files_only': True},
64
+ )
65
+ except OSError as e: # noqa
66
+ pass
67
+ else:
68
+ return local
69
+
70
+ if ctx.local_config_present_is_authoritative:
71
+ try:
72
+ local_config = orig_cached_files(
73
+ path_or_repo_id,
74
+ [tfm.CONFIG_NAME],
75
+ **{**kwargs, 'local_files_only': True},
76
+ )
77
+ except OSError as e: # noqa
78
+ pass
79
+ else:
80
+ raise OSError(
81
+ f'Files {filenames!r} requested under local_first '
82
+ f'but local_config present at {local_config!r}, '
83
+ f'assuming files do not exist.',
84
+ )
85
+
86
+ return orig_cached_files(path_or_repo_id, filenames, **kwargs)
87
+
88
+ cached_files.__code__ = create_detour(cached_files, new_cached_files, as_kwargs=True)
89
+
90
+
91
+ @contextlib.contextmanager
92
+ def file_cache_patch_context(
93
+ *,
94
+ local_first: bool = False,
95
+ local_config_present_is_authoritative: bool = False,
96
+ ) -> ta.Generator[None]:
97
+ patch_file_cache()
98
+
99
+ new_ctx = dc.replace(
100
+ old_ctx := _get_file_cache_patch_context(),
101
+ local_first=local_first,
102
+ local_config_present_is_authoritative=local_config_present_is_authoritative,
103
+ )
104
+
105
+ _FILE_CACHE_PATCH_CONTEXT_TLS.context = new_ctx
106
+ try:
107
+ yield
108
+ finally:
109
+ _FILE_CACHE_PATCH_CONTEXT_TLS.context = old_ctx
ommlds/cli/main.py CHANGED
@@ -39,10 +39,6 @@ else:
39
39
 
40
40
 
41
41
  async def _a_main(args: ta.Any = None) -> None:
42
- logs.configure_standard_logging('INFO')
43
-
44
- #
45
-
46
42
  parser = argparse.ArgumentParser()
47
43
  parser.add_argument('prompt', nargs='*')
48
44
 
@@ -64,6 +60,8 @@ async def _a_main(args: ta.Any = None) -> None:
64
60
  parser.add_argument('-E', '--embed', action='store_true')
65
61
  parser.add_argument('-j', '--image', action='store_true')
66
62
 
63
+ parser.add_argument('-v', '--verbose', action='store_true')
64
+
67
65
  parser.add_argument('--enable-fs-tools', action='store_true')
68
66
  parser.add_argument('--enable-todo-tools', action='store_true')
69
67
  parser.add_argument('--enable-unsafe-tools-do-not-use-lol', action='store_true')
@@ -74,6 +72,14 @@ async def _a_main(args: ta.Any = None) -> None:
74
72
 
75
73
  #
76
74
 
75
+ if args.verbose:
76
+ logs.configure_standard_logging('DEBUG')
77
+ else:
78
+ logs.configure_standard_logging('INFO')
79
+ logs.silence_noisy_loggers()
80
+
81
+ #
82
+
77
83
  content: mc.Content | None
78
84
 
79
85
  if args.image:
@@ -161,7 +167,7 @@ async def _a_main(args: ta.Any = None) -> None:
161
167
  args.enable_test_weather_tool or
162
168
  args.code
163
169
  ),
164
- enabled_tools={
170
+ enabled_tools={ # noqa
165
171
  *(['fs'] if args.enable_fs_tools else []),
166
172
  *(['todo'] if args.enable_todo_tools else []),
167
173
  *(['weather'] if args.enable_test_weather_tool else []),
@@ -32,7 +32,7 @@ class _CatalogBackendProvider(BackendProvider[ServiceT], lang.Abstract):
32
32
  @contextlib.asynccontextmanager
33
33
  async def _provide_backend(self, cls: type[ServiceT]) -> ta.AsyncIterator[ServiceT]:
34
34
  service: ServiceT
35
- async with lang.async_or_sync_maybe_managing(self._catalog.get_backend(
35
+ async with lang.async_or_sync_maybe_managing(self._catalog.new_backend(
36
36
  cls,
37
37
  self._name,
38
38
  *(self._configs or []),
@@ -31,7 +31,7 @@ class CompletionSession(Session['CompletionSession.Config']):
31
31
  prompt = check.isinstance(self._config.content, str)
32
32
 
33
33
  mdl: mc.CompletionService
34
- async with lang.async_maybe_managing(self._backend_catalog.get_backend(
34
+ async with lang.async_maybe_managing(self._backend_catalog.new_backend(
35
35
  mc.CompletionService,
36
36
  self._config.backend or DEFAULT_COMPLETION_MODEL_BACKEND,
37
37
  )) as mdl:
@@ -29,7 +29,7 @@ class EmbeddingSession(Session['EmbeddingSession.Config']):
29
29
 
30
30
  async def run(self) -> None:
31
31
  mdl: mc.EmbeddingService
32
- async with lang.async_maybe_managing(self._backend_catalog.get_backend(
32
+ async with lang.async_maybe_managing(self._backend_catalog.new_backend(
33
33
  mc.EmbeddingService,
34
34
  self._config.backend or DEFAULT_EMBEDDING_MODEL_BACKEND,
35
35
  )) as mdl:
@@ -322,6 +322,7 @@ with _lang.auto_proxy_init(
322
322
  ##
323
323
 
324
324
  from .registries.globals import ( # noqa
325
+ get_registry_cls,
325
326
  register_type,
326
327
  registry_new,
327
328
  registry_of,
@@ -3,15 +3,28 @@ import typing as ta
3
3
 
4
4
  from omlish import lang
5
5
 
6
+ from ...configs import Config
7
+
8
+
9
+ T = ta.TypeVar('T')
10
+
6
11
 
7
12
  ##
8
13
 
9
14
 
10
15
  class BackendCatalog(lang.Abstract):
16
+ class Backend(ta.NamedTuple):
17
+ factory: ta.Callable[..., ta.Any]
18
+ configs: ta.Sequence[Config] | None
19
+
11
20
  @abc.abstractmethod
12
- def get_backend(self, service_cls: ta.Any, name: str, *args: ta.Any, **kwargs: ta.Any) -> ta.Any:
21
+ def get_backend(self, service_cls: type[T], name: str) -> Backend:
13
22
  raise NotImplementedError
14
23
 
24
+ def new_backend(self, service_cls: ta.Any, name: str, *args: ta.Any, **kwargs: ta.Any) -> ta.Any:
25
+ be = self.get_backend(service_cls, name)
26
+ return be.factory(*be.configs or [], *args, **kwargs)
27
+
15
28
  # #
16
29
  #
17
30
  # class Bound(lang.Final, ta.Generic[T]):
@@ -40,9 +40,9 @@ class SimpleBackendCatalog(BackendCatalog):
40
40
  sc_dct[e.name] = e
41
41
  self._dct = dct
42
42
 
43
- def get_backend(self, service_cls: ta.Any, name: str, *args: ta.Any, **kwargs: ta.Any) -> ta.Any:
43
+ def get_backend(self, service_cls: ta.Any, name: str, *args: ta.Any, **kwargs: ta.Any) -> BackendCatalog.Backend:
44
44
  e = self._dct[service_cls][name]
45
- return e.factory_fn(*args, **kwargs)
45
+ return BackendCatalog.Backend(e.factory_fn, None)
46
46
 
47
47
 
48
48
  ##
@@ -5,7 +5,7 @@ from omlish import check
5
5
  from ...models.configs import ModelPath
6
6
  from ...models.configs import ModelRepo
7
7
  from ...models.repos.resolving import ModelRepoResolver
8
- from ...registries.globals import registry_new
8
+ from ...registries.globals import get_registry_cls
9
9
  from ..strings.parsing import parse_backend_string
10
10
  from ..strings.resolving import BackendStringResolver
11
11
  from ..strings.resolving import ResolveBackendStringArgs
@@ -30,14 +30,14 @@ class BackendStringBackendCatalog(BackendCatalog):
30
30
  self._string_resolver = string_resolver
31
31
  self._model_repo_resolver = model_repo_resolver
32
32
 
33
- def get_backend(self, service_cls: ta.Any, name: str, *args: ta.Any, **kwargs: ta.Any) -> ta.Any:
33
+ def get_backend(self, service_cls: ta.Any, name: str, *args: ta.Any, **kwargs: ta.Any) -> BackendCatalog.Backend:
34
34
  ps = parse_backend_string(name)
35
35
  rs = check.not_none(self._string_resolver.resolve_backend_string(ResolveBackendStringArgs(
36
36
  service_cls,
37
37
  ps,
38
38
  )))
39
39
 
40
- al = list(rs.args or [])
40
+ al: list = list(rs.args or [])
41
41
 
42
42
  # FIXME: lol
43
43
  if al and isinstance(al[0], ModelRepo):
@@ -46,10 +46,12 @@ class BackendStringBackendCatalog(BackendCatalog):
46
46
  mrp = check.not_none(mrr.resolve(mr))
47
47
  al = [ModelPath(mrp.path), *al[1:]]
48
48
 
49
- return registry_new(
49
+ cls = get_registry_cls(
50
50
  service_cls,
51
51
  rs.name,
52
- *al,
53
- *args,
54
- **kwargs,
52
+ )
53
+
54
+ return BackendCatalog.Backend(
55
+ cls,
56
+ al,
55
57
  )
@@ -95,8 +95,7 @@ class AnthropicChatChoicesStreamService:
95
95
  db = DelimitingBuffer([b'\r', b'\n', b'\r\n'])
96
96
  sd = sse.SseDecoder()
97
97
  while True:
98
- # FIXME: read1 not on response stream protocol
99
- b = http_response.stream.read1(self.READ_CHUNK_SIZE) # type: ignore[attr-defined]
98
+ b = http_response.stream.read1(self.READ_CHUNK_SIZE)
100
99
  for l in db.feed(b):
101
100
  if isinstance(l, DelimitingBuffer.Incomplete):
102
101
  # FIXME: handle
@@ -169,8 +169,7 @@ class GoogleChatChoicesStreamService:
169
169
  async def inner(sink: StreamResponseSink[AiChoicesDeltas]) -> ta.Sequence[ChatChoicesOutputs] | None:
170
170
  db = DelimitingBuffer([b'\r', b'\n', b'\r\n'])
171
171
  while True:
172
- # FIXME: read1 not on response stream protocol
173
- b = http_response.stream.read1(self.READ_CHUNK_SIZE) # type: ignore[attr-defined]
172
+ b = http_response.stream.read1(self.READ_CHUNK_SIZE)
174
173
  for bl in db.feed(b):
175
174
  if isinstance(bl, DelimitingBuffer.Incomplete):
176
175
  # FIXME: handle
@@ -54,9 +54,12 @@ class BaseOllamaChatChoicesService(lang.Abstract):
54
54
  def __init__(
55
55
  self,
56
56
  *configs: ApiUrl | ModelName,
57
+ http_client: http.AsyncHttpClient | None = None,
57
58
  ) -> None:
58
59
  super().__init__()
59
60
 
61
+ self._http_client = http_client
62
+
60
63
  with tv.consume(*configs) as cc:
61
64
  self._api_url = cc.pop(self.DEFAULT_API_URL)
62
65
  self._model_name = cc.pop(self.DEFAULT_MODEL_NAME)
@@ -111,10 +114,11 @@ class OllamaChatChoicesService(BaseOllamaChatChoicesService):
111
114
 
112
115
  raw_request = msh.marshal(a_req)
113
116
 
114
- raw_response = http.request(
115
- self._api_url.v.removesuffix('/') + '/chat',
116
- data=json.dumps(raw_request).encode('utf-8'),
117
- )
117
+ async with http.manage_async_client(self._http_client) as http_client:
118
+ raw_response = await http_client.request(http.HttpRequest(
119
+ self._api_url.v.removesuffix('/') + '/chat',
120
+ data=json.dumps(raw_request).encode('utf-8'),
121
+ ))
118
122
 
119
123
  json_response = json.loads(check.not_none(raw_response.data).decode('utf-8'))
120
124
 
@@ -165,14 +169,13 @@ class OllamaChatChoicesStreamService(BaseOllamaChatChoicesService):
165
169
  )
166
170
 
167
171
  async with UseResources.or_new(request.options) as rs:
168
- http_client = rs.enter_context(http.client())
169
- http_response = rs.enter_context(http_client.stream_request(http_request))
172
+ http_client = await rs.enter_async_context(http.manage_async_client(self._http_client))
173
+ http_response = await rs.enter_async_context(await http_client.stream_request(http_request))
170
174
 
171
175
  async def inner(sink: StreamResponseSink[AiChoicesDeltas]) -> ta.Sequence[ChatChoicesOutputs] | None:
172
176
  db = DelimitingBuffer([b'\r', b'\n', b'\r\n'])
173
177
  while True:
174
- # FIXME: read1 not on response stream protocol
175
- b = http_response.stream.read1(self.READ_CHUNK_SIZE) # type: ignore[attr-defined]
178
+ b = await http_response.stream.read1(self.READ_CHUNK_SIZE)
176
179
  for l in db.feed(b):
177
180
  if isinstance(l, DelimitingBuffer.Incomplete):
178
181
  # FIXME: handle
@@ -88,8 +88,7 @@ class OpenaiChatChoicesStreamService:
88
88
  db = DelimitingBuffer([b'\r', b'\n', b'\r\n'])
89
89
  sd = sse.SseDecoder()
90
90
  while True:
91
- # FIXME: read1 not on response stream protocol
92
- b = http_response.stream.read1(self.READ_CHUNK_SIZE) # type: ignore[attr-defined]
91
+ b = http_response.stream.read1(self.READ_CHUNK_SIZE)
93
92
  for l in db.feed(b):
94
93
  if isinstance(l, DelimitingBuffer.Incomplete):
95
94
  # FIXME: handle
@@ -4,6 +4,7 @@ TODO:
4
4
  - https://huggingface.co/blog/aifeifei798/transformers-streaming-output
5
5
  """
6
6
  import sys
7
+ import threading
7
8
  import typing as ta
8
9
 
9
10
  import transformers as tfm
@@ -11,7 +12,10 @@ import transformers as tfm
11
12
  from omlish import check
12
13
  from omlish import lang
13
14
  from omlish import typedvalues as tv
15
+ from omlish.asyncs.asyncio.sync import AsyncioBufferRelay
14
16
 
17
+ from .....backends.transformers.filecache import file_cache_patch_context
18
+ from .....backends.transformers.streamers import CancellableTextStreamer
15
19
  from ....chat.choices.services import ChatChoicesRequest
16
20
  from ....chat.choices.services import ChatChoicesResponse
17
21
  from ....chat.choices.services import static_check_is_chat_choices_service
@@ -177,10 +181,14 @@ class BaseTransformersChatChoicesService(lang.ExitStacked):
177
181
  for pkw_cfg in self._pipeline_kwargs:
178
182
  pkw.update(pkw_cfg.v)
179
183
 
180
- return tfm.pipeline(
181
- 'text-generation',
182
- **pkw,
183
- )
184
+ with file_cache_patch_context(
185
+ local_first=True,
186
+ local_config_present_is_authoritative=True,
187
+ ):
188
+ return tfm.pipeline(
189
+ 'text-generation',
190
+ **pkw,
191
+ )
184
192
 
185
193
 
186
194
  ##
@@ -232,29 +240,59 @@ class TransformersChatChoicesStreamService(BaseTransformersChatChoicesService):
232
240
  for m in request.v
233
241
  ]
234
242
 
243
+ relay: AsyncioBufferRelay = AsyncioBufferRelay()
244
+
245
+ def streamer_callback(text: str, *, stream_end: bool) -> None:
246
+ if text or stream_end:
247
+ relay.push(text, *([None] if stream_end else []))
248
+
249
+ streamer = CancellableTextStreamer(
250
+ check.not_none(pipeline.tokenizer), # type: ignore[arg-type]
251
+ streamer_callback, # noqa
252
+ skip_prompt=True,
253
+ skip_special_tokens=True,
254
+ )
255
+
235
256
  async with UseResources.or_new(request.options) as rs:
257
+ thread = threading.Thread(
258
+ target=CancellableTextStreamer.ignoring_cancelled(pipeline),
259
+ args=(
260
+ inputs,
261
+ ),
262
+ kwargs=dict(
263
+ streamer=streamer,
264
+ ),
265
+ )
266
+
267
+ def stop_thread() -> None:
268
+ streamer.cancel()
269
+ # thread.join()
270
+
271
+ rs.enter_context(lang.defer(stop_thread))
272
+
273
+ thread.start()
274
+
236
275
  async def inner(sink: StreamResponseSink[AiChoicesDeltas]) -> ta.Sequence[ChatChoicesOutputs] | None:
237
- # last_role: ta.Any = None
238
- #
239
- # for chunk in output:
240
- # check.state(chunk['object'] == 'chat.completion.chunk')
241
- #
242
- # choice = check.single(chunk['choices'])
243
- #
244
- # if not (delta := choice.get('delta', {})):
245
- # continue
246
- #
247
- # # FIXME: check role is assistant
248
- # if (role := delta.get('role')) != last_role:
249
- # last_role = role
250
- #
251
- # # FIXME: stop reason
252
- #
253
- # if (content := delta.get('content', '')):
254
- # await sink.emit(AiChoicesDeltas([AiChoiceDeltas([ContentAiChoiceDelta(content)])]))
255
- #
256
- # return None
257
-
258
- raise NotImplementedError
276
+ while True:
277
+ await relay.wait()
278
+ got = relay.swap()
279
+
280
+ if not got:
281
+ raise RuntimeError
282
+
283
+ if got[-1] is None:
284
+ out = ''.join(got[:-1])
285
+ end = True
286
+ else:
287
+ out = ''.join(got)
288
+ end = False
289
+
290
+ if out:
291
+ await sink.emit(AiChoicesDeltas([AiChoiceDeltas([ContentAiChoiceDelta(out)])]))
292
+
293
+ if end:
294
+ break
295
+
296
+ return []
259
297
 
260
298
  return await new_stream_response(rs, inner)
@@ -98,20 +98,34 @@ def register_type(
98
98
 
99
99
 
100
100
  @ta.overload
101
- def registry_new(cls: type[T], name: str, *args: ta.Any, **kwargs: ta.Any) -> T:
101
+ def get_registry_cls(cls: type[T], name: str) -> type[T]:
102
102
  ...
103
103
 
104
104
 
105
105
  @ta.overload
106
- def registry_new(cls: ta.Any, name: str, *args: ta.Any, **kwargs: ta.Any) -> ta.Any:
106
+ def get_registry_cls(cls: ta.Any, name: str) -> ta.Any:
107
107
  ...
108
108
 
109
109
 
110
- def registry_new(cls, name, *args, **kwargs):
110
+ def get_registry_cls(cls, name, *args, **kwargs):
111
111
  be_cls = _GlobalRegistry.instance().get_registry_cls(cls, name)
112
112
  if isinstance(cls, type):
113
113
  be_cls = check.issubclass(be_cls, cls) # noqa
114
- return be_cls(*args, **kwargs)
114
+ return be_cls
115
+
116
+
117
+ @ta.overload
118
+ def registry_new(cls: type[T], name: str, *args: ta.Any, **kwargs: ta.Any) -> T:
119
+ ...
120
+
121
+
122
+ @ta.overload
123
+ def registry_new(cls: ta.Any, name: str, *args: ta.Any, **kwargs: ta.Any) -> ta.Any:
124
+ ...
125
+
126
+
127
+ def registry_new(cls, name, *args, **kwargs):
128
+ return get_registry_cls(cls, name)(*args, **kwargs)
115
129
 
116
130
 
117
131
  #
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ommlds
3
- Version: 0.0.0.dev468
3
+ Version: 0.0.0.dev469
4
4
  Summary: ommlds
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -14,8 +14,8 @@ Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Python: >=3.13
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
- Requires-Dist: omdev==0.0.0.dev468
18
- Requires-Dist: omlish==0.0.0.dev468
17
+ Requires-Dist: omdev==0.0.0.dev469
18
+ Requires-Dist: omlish==0.0.0.dev469
19
19
  Provides-Extra: all
20
20
  Requires-Dist: llama-cpp-python~=0.3; extra == "all"
21
21
  Requires-Dist: mlx~=0.29; extra == "all"
@@ -1,9 +1,12 @@
1
- ommlds/.omlish-manifests.json,sha256=u1WF90X6xpzZW21a4h5zzPyP4a3T30V08RjQz5HGABM,21555
1
+ ommlds/.omlish-manifests.json,sha256=K1CQFRaaQ43_zlr1ekl2h-CMXQ_U9zA0xBIOB-e_u-8,21555
2
2
  ommlds/__about__.py,sha256=t2rQF0yXpWFcCb2dvgzGR3I35HKGvGSn-EfhaUWVl5s,1759
3
3
  ommlds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  ommlds/huggingface.py,sha256=JfEyfKOxU3-SY_ojtXBJFNeD-NIuKjvMe3GL3e93wNA,1175
5
- ommlds/_hacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- ommlds/_hacks/patches.py,sha256=HhoB-9IosLTgX1RANaEbyTTDolnqe1J84e2W0mSlmF8,2060
5
+ ommlds/_hacks/__init__.py,sha256=ajfw7dMKH8UuloeQ5MSxWwgAmdWf2v8gm-K3uLP9wtY,196
6
+ ommlds/_hacks/funcs.py,sha256=8XseIblP7yolDUD7WQSGn1LP90IQzByVejSzphAPDyM,2861
7
+ ommlds/_hacks/names.py,sha256=01XSF-Rd0nLGb7oA0Jg1R9MtkOk0jfUhIO5CPyA-s6M,4690
8
+ ommlds/_hacks/params.py,sha256=FihwXN6RAvQR1HqEemTRL_ivEr8WOlirH1sZ-lM3vgM,1725
9
+ ommlds/_hacks/patches.py,sha256=Dsz4GcgRXd1zi18jiDO2C_8IF12VTsysjthiOQz-h80,1871
7
10
  ommlds/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
11
  ommlds/backends/anthropic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
12
  ommlds/backends/anthropic/protocol/__init__.py,sha256=bWNQbfEt7jLss6s03c0sBRCsx32POdgkO5VeNe0K3SU,132
@@ -78,11 +81,12 @@ ommlds/backends/torch/backends.py,sha256=Bo-ZdW1n9NswvptT8bL9CssEOKwusDuBMaXVjRS
78
81
  ommlds/backends/torch/devices.py,sha256=KWkeyArPdUwVqckQTJPkN-4GQdv39cpOgCMv_XfkLkQ,776
79
82
  ommlds/backends/torch/purge.py,sha256=sp6XUxNLoVCepxIPKw3tevHn-cQqgorILvIQzixauiI,1834
80
83
  ommlds/backends/transformers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
84
+ ommlds/backends/transformers/filecache.py,sha256=ycfswt7f4qRrPSTFRhofXZaDBuDPpypEKwXzSBsBsu8,3317
81
85
  ommlds/backends/transformers/streamers.py,sha256=Hu_9lp_kUilKjOfs7Ixqr2NoA5FuRn2eRh8JdvaBDYc,1688
82
86
  ommlds/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
87
  ommlds/cli/__main__.py,sha256=1ffCb0fcUOJMzxROJmJRXQ8PSOVYv7KrcuBtT95cf0c,140
84
88
  ommlds/cli/inject.py,sha256=WhTDabJz9b1NRRHVH-UyVN5nj6UncvIeTvgkGrcE9vc,666
85
- ommlds/cli/main.py,sha256=rOsdlBHHiF5ZjMBXSNojXFyiWin7pN6RJMZUwGEyXVs,5608
89
+ ommlds/cli/main.py,sha256=dTBJSxWdsS1pEqDY-vT_g2PC-aUkatVhq0XEW8zirQ0,5802
86
90
  ommlds/cli/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
87
91
  ommlds/cli/backends/inject.py,sha256=OVstNsoeVnprM9PBL_zP0N46KkoDg3_Wz90BWcQ7km4,1734
88
92
  ommlds/cli/backends/standard.py,sha256=HnammWyAXJHeqXJrAMBdarcT4Nyt2CxudZdD2fW_Y9M,631
@@ -95,7 +99,7 @@ ommlds/cli/sessions/chat/driver.py,sha256=ddnCYTKqWiPxV8U4UbFwb7E3yi81ItjZ9j3AJd
95
99
  ommlds/cli/sessions/chat/inject.py,sha256=7Yg6wUs2Oej4UjNZCAWCJCEsDJZWvT4G8XvkvVUMC7U,1928
96
100
  ommlds/cli/sessions/chat/session.py,sha256=eqwelLE74JFC-fBpk_hdwMD2nP4pLv3ZPwUn99200B8,521
97
101
  ommlds/cli/sessions/chat/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
- ommlds/cli/sessions/chat/backends/catalog.py,sha256=gc03dqXEUUSi4WCWJ30HrkHPWlAkZHXkj1pOq7KVakU,1764
102
+ ommlds/cli/sessions/chat/backends/catalog.py,sha256=-mth_gw2MTnlClGVIdjiOJn1g4B6G9SqZDsmg5Rg70Y,1764
99
103
  ommlds/cli/sessions/chat/backends/inject.py,sha256=VbZ-Fb679kTItRpAhIYCqSM8vXUFeRDQWssUfrFgGi8,882
100
104
  ommlds/cli/sessions/chat/backends/injection.py,sha256=GCn5OvNIEowgB70kQVuU84z3i8lLA4vOVkTZlQG8s0o,327
101
105
  ommlds/cli/sessions/chat/backends/types.py,sha256=5eImYHXLKqbC5MDrN443eMGamP9snCmV1n7LtAsqgPk,696
@@ -140,18 +144,18 @@ ommlds/cli/sessions/chat/tools/weather.py,sha256=vZXOHdRGGlkDEXasW5foc58MyEMOc79
140
144
  ommlds/cli/sessions/completion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
141
145
  ommlds/cli/sessions/completion/configs.py,sha256=KeOmvNrq6KkI96FaRRPnpWNx3yDlD-FgaiOwPEL9HPU,245
142
146
  ommlds/cli/sessions/completion/inject.py,sha256=qpyp2Ro0sPOIOssk-7eXOseKG1Fu_vf1zvyLjZi5qIE,564
143
- ommlds/cli/sessions/completion/session.py,sha256=YLq9beHxfgCAu8t9Xj54qQxXj8ebwqrcN8JsJ3_2KOw,1067
147
+ ommlds/cli/sessions/completion/session.py,sha256=H4k9_iWiseHcgTBURG5S9LLVJ7TkONA-AYu50WSpHp4,1067
144
148
  ommlds/cli/sessions/embedding/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
145
149
  ommlds/cli/sessions/embedding/configs.py,sha256=WwWwJ7GpUYUEOPcYr2EhNLV8m1cK6llp5N_bMnFX_cw,243
146
150
  ommlds/cli/sessions/embedding/inject.py,sha256=XYjqDT5GajZ0LNks36aZRNNKhH1m-xfAL1bbMxfISYQ,559
147
- ommlds/cli/sessions/embedding/session.py,sha256=SccMICjbS1BL7wMkDzd17d2TWRjbzAmMwFn_CjC2-a8,1039
151
+ ommlds/cli/sessions/embedding/session.py,sha256=BOaDRK40LjTGqz6piCMdxY3yQB5MSaUpWTJcWYNL5Yw,1039
148
152
  ommlds/cli/state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
153
  ommlds/cli/state/inject.py,sha256=-wqovpgxLYBpJkkCzscn2o6F6AD-agF8PoNjVac6FuQ,702
150
154
  ommlds/cli/state/storage.py,sha256=tRPmgCANRrw7A5Qr700OaH58F6S96O37I8Ivrbo7_gI,3001
151
155
  ommlds/datasets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
152
156
  ommlds/datasets/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
153
157
  ommlds/datasets/lib/movies.py,sha256=LmdfoXsZU9XMM_r-sxCLv_s06BFzwWO4xUj6sc9XVcI,1961
154
- ommlds/minichain/__init__.py,sha256=5S2GfZW4qWF1fin2Ee8YHT4XuD_vEvtCVWTIXHOGrwo,11016
158
+ ommlds/minichain/__init__.py,sha256=uruXAyfKzg_Ed3ZPkiNVopZugZV62-eqPOT1EtxljiA,11042
155
159
  ommlds/minichain/_marshal.py,sha256=n9PGWrHhvAmGIc7KDOYt3IF9Z6G0ncXskyICTp3Ji6k,1923
156
160
  ommlds/minichain/_typedvalues.py,sha256=Vl1Edt5khC0e5RPFBPmPCxn0IzrfVd0NHzAjAN2E6Kc,2183
157
161
  ommlds/minichain/completion.py,sha256=lQ0LfCIYZsvDqteHhhDIv16D2_gn_xMfEL0ouywE5Yo,1033
@@ -166,9 +170,9 @@ ommlds/minichain/types.py,sha256=K6RRjpUi17UEG0cqPrrvbVANU0iRVh3WLiH-y6oEWFI,414
166
170
  ommlds/minichain/utils.py,sha256=NTsBu_pSZnLdZc1R1Se70rb_9J-IoB6VRwjhwzh3PwY,490
167
171
  ommlds/minichain/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
168
172
  ommlds/minichain/backends/catalogs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
169
- ommlds/minichain/backends/catalogs/base.py,sha256=Yw9K2A1zSFzQqZjqW5s0IV6h9DnbyT8LfDQpYaIfv2w,882
170
- ommlds/minichain/backends/catalogs/simple.py,sha256=KJLKEOYqzsekchxEjqIL0yWqlGvUu97PsRvQUIoXXc4,1472
171
- ommlds/minichain/backends/catalogs/strings.py,sha256=G7oQPaPfwBQ1CUNVvptW8M-ipesYXwAtS88UbOK2ZHw,1714
173
+ ommlds/minichain/backends/catalogs/base.py,sha256=TNdFrYYFEwp-rbmp-VHxUKIFCiVYhFPcu4PNhSaEHMA,1239
174
+ ommlds/minichain/backends/catalogs/simple.py,sha256=T6GeY902XPRjNnwX1AivunpkirLyxFg5rG2V2LA0Puo,1501
175
+ ommlds/minichain/backends/catalogs/strings.py,sha256=IHid5yRbHvkU5O5ypSMWAPcETLlvj1CXeIJ3mHrDyi8,1768
172
176
  ommlds/minichain/backends/impls/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
173
177
  ommlds/minichain/backends/impls/mistral.py,sha256=I_HTwXqAoQi2xyw_nLTeUamtOZLLl-oQZ234AVJZZLA,2649
174
178
  ommlds/minichain/backends/impls/sqlite.py,sha256=NOFm_fgr-OZ8mo7etj0zwvxsDnidRwKzhdDom58e6ks,2157
@@ -176,14 +180,14 @@ ommlds/minichain/backends/impls/anthropic/__init__.py,sha256=47DEQpj8HBSa-_TImW-
176
180
  ommlds/minichain/backends/impls/anthropic/chat.py,sha256=LVaRP_Pbz4UghSHD8GZ22hMWE4Rsd_6bSysgl2BR_AM,4166
177
181
  ommlds/minichain/backends/impls/anthropic/names.py,sha256=GPPeYt0CcDcDCR8I6BMd7bMjC_Zk_bjnLLpF9ClwXcg,1099
178
182
  ommlds/minichain/backends/impls/anthropic/protocol.py,sha256=whPVYuKShKiMCzasHl77sCIiymhzXj8mFZXEyhZvld8,3292
179
- ommlds/minichain/backends/impls/anthropic/stream.py,sha256=AvoLk25R7E_aSS1tAN-P-UKjhKPxYtQoeGakXvFdblI,8677
183
+ ommlds/minichain/backends/impls/anthropic/stream.py,sha256=4xa1LYsa1LLGYWlP2-RMk1ll4eyikkjlfJZ1fU5EEPM,8580
180
184
  ommlds/minichain/backends/impls/duckduckgo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
181
185
  ommlds/minichain/backends/impls/duckduckgo/search.py,sha256=igzeU9P9b1MMiu4KAJVS9H6KLIoPm68wXi4Kx3_DHyQ,940
182
186
  ommlds/minichain/backends/impls/google/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
183
187
  ommlds/minichain/backends/impls/google/chat.py,sha256=q6LasmAh3Xn78kNlgpgwoKhdTj3o76j0X3_xitdyAE0,6316
184
188
  ommlds/minichain/backends/impls/google/names.py,sha256=HxHJ31HeKZg6aW1C_Anqp-gamCXpq9pOdKj8_yVgE8Y,871
185
189
  ommlds/minichain/backends/impls/google/search.py,sha256=5-2nAZ1QmbqHSQcwWnqqcgCM-Duy2ryctJEIv2tcpZg,3260
186
- ommlds/minichain/backends/impls/google/stream.py,sha256=Mhg5cOe7PKbnlQURyk2IRermtpzxU5Y0j3w4fkt2ZRg,7900
190
+ ommlds/minichain/backends/impls/google/stream.py,sha256=8k-8OfX4EuGtRewKx7VFLVeH3YAuF5t6EWVSoH8-VPU,7803
187
191
  ommlds/minichain/backends/impls/google/tools.py,sha256=Tty0gsyx7-PbeoNqMuql_ewQ6q-ZsDaDdsD5ShinGVY,5089
188
192
  ommlds/minichain/backends/impls/huggingface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
189
193
  ommlds/minichain/backends/impls/huggingface/configs.py,sha256=6jsBtPNXOP57PcpxNTVLGWLc-18Iwn_lDbGouwCJTIQ,258
@@ -196,14 +200,14 @@ ommlds/minichain/backends/impls/llamacpp/stream.py,sha256=uzrXr2HhshgFe3Z0g8KTPc
196
200
  ommlds/minichain/backends/impls/mlx/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
197
201
  ommlds/minichain/backends/impls/mlx/chat.py,sha256=sMlhgiFZrxAC-kKkLSJ6c-2uJn0IHZXH4EiPET_-CKI,7458
198
202
  ommlds/minichain/backends/impls/ollama/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
199
- ommlds/minichain/backends/impls/ollama/chat.py,sha256=UK19riOph-ptIz9zW7PucGWvVEtWHOHvwp7hoKurDNw,6393
203
+ ommlds/minichain/backends/impls/ollama/chat.py,sha256=l9agVFvVmB0j8SaE62Yx2ItiR55HOVnKDrFPTXltP9E,6590
200
204
  ommlds/minichain/backends/impls/openai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
201
205
  ommlds/minichain/backends/impls/openai/chat.py,sha256=eMRjxPNrzrRjaw83LJuYzP9DGvwGyY2ObJSZub4Z9bY,2658
202
206
  ommlds/minichain/backends/impls/openai/completion.py,sha256=0XTC08mZzbW23Y2DNW2xfRR0eDX4nTyejF8CR1BdHZs,1756
203
207
  ommlds/minichain/backends/impls/openai/embedding.py,sha256=kkDJ3_0EqwQ_E0eXsSH1TuWXQmRqaijK8zG90fnlf3s,1582
204
208
  ommlds/minichain/backends/impls/openai/format.py,sha256=teGX8mNU3sXNWP4YWGD8d59M4X9_r75ImSzfTJgtNCM,7351
205
209
  ommlds/minichain/backends/impls/openai/names.py,sha256=b74t8FwSbGEveVtVz4SqM5tiRDyTKNlUKlseV6AX3Yo,1211
206
- ommlds/minichain/backends/impls/openai/stream.py,sha256=M7II7kZFsy33j8NQwdM1CCeKet3lw-XLOQdDzrzn-Yo,5297
210
+ ommlds/minichain/backends/impls/openai/stream.py,sha256=AkALgjkALmWd3FaeXdLlPilI8JiW4lpJdknISt0gS-4,5200
207
211
  ommlds/minichain/backends/impls/sentencepiece/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
208
212
  ommlds/minichain/backends/impls/sentencepiece/tokens.py,sha256=tUEBKyBgkTowssS_AdcAuPkyFzfyDfE935x4JG8PXM0,1602
209
213
  ommlds/minichain/backends/impls/tinygrad/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -213,7 +217,7 @@ ommlds/minichain/backends/impls/tokenizers/tokens.py,sha256=_8Q49k5YroG5wQI0cuK6
213
217
  ommlds/minichain/backends/impls/transformers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
214
218
  ommlds/minichain/backends/impls/transformers/sentence.py,sha256=1bFJ-ND3MOkj7mNsPuISrQCpqTs7npmmNmYcc2go-Fk,1393
215
219
  ommlds/minichain/backends/impls/transformers/tokens.py,sha256=uS3-IWOJRUMBfPDVRrp3SCaXdE1yzEdKHQcyv0JZQIw,2089
216
- ommlds/minichain/backends/impls/transformers/transformers.py,sha256=U4O-MiVH3dRXf-UNSoKZueZVM8XvAm2mMr30qQUHhFY,8000
220
+ ommlds/minichain/backends/impls/transformers/transformers.py,sha256=laM8G2SAE6jUjnHkeZsbWxS2KJF4efi-35aBlRBzIsE,9053
217
221
  ommlds/minichain/backends/strings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
218
222
  ommlds/minichain/backends/strings/manifests.py,sha256=kmlanVUAZqIh0P95Mm8H20e8ib3gEgYHHUlkCXDQGFk,413
219
223
  ommlds/minichain/backends/strings/parsing.py,sha256=2wChk9Z8fhqJTk8_91f8QFjKcSZygOQM_rVk-P4NnKw,1772
@@ -302,7 +306,7 @@ ommlds/minichain/models/names.py,sha256=SqXrOkSFTI2VkfA5puGGb0EFg2TvvNZpJgTF7eS6
302
306
  ommlds/minichain/models/repos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
303
307
  ommlds/minichain/models/repos/resolving.py,sha256=I8l8osTJNE0mT5nmb7tYhOfNH0f-F3JQVkvIrjLPvOE,602
304
308
  ommlds/minichain/registries/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
305
- ommlds/minichain/registries/globals.py,sha256=oibPBjAO1MMemcaV6NdOLGenjB820sBvdLoL4je5CJU,2973
309
+ ommlds/minichain/registries/globals.py,sha256=M4-RTsjHfm7FRXqV-4ecWywEF1Di2lnTn3a7OJhtzkU,3224
306
310
  ommlds/minichain/registries/manifests.py,sha256=GTWk4lssAk8mmG3ilGK2NvIU-rGS3otOZNuGQUDStMI,362
307
311
  ommlds/minichain/registries/registry.py,sha256=wmk88NsM20Kl4PduX3Oy5roHPfNKtXENCITTc7M8gAY,4626
308
312
  ommlds/minichain/services/__init__.py,sha256=gjhYyT7-MY1PISdHMKmfk2o_QrdU7UV7I9ZNh2Yjpu4,336
@@ -373,9 +377,9 @@ ommlds/wiki/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
373
377
  ommlds/wiki/utils/io.py,sha256=UKgDJGtmpnWvIqVd2mJc2QNPOqlToEY1GEveNp6_pMo,7088
374
378
  ommlds/wiki/utils/progress.py,sha256=EhvKcMFYtsarCQhIahlO6f0SboyAKP3UwUyrnVnP-Vk,3222
375
379
  ommlds/wiki/utils/xml.py,sha256=vVV8Ctn13aaRM9eYfs9Wd6rHn5WOCEUzQ44fIhOvJdg,3754
376
- ommlds-0.0.0.dev468.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
377
- ommlds-0.0.0.dev468.dist-info/METADATA,sha256=k1H1yGwCqmZETx1eTEKBsNZ_whn2QWxWap9pdErGIkw,3224
378
- ommlds-0.0.0.dev468.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
379
- ommlds-0.0.0.dev468.dist-info/entry_points.txt,sha256=Z5YWtX7ClfiCKdW-dd_CSVvM0h4yQpJPi-2G3q6gNFo,35
380
- ommlds-0.0.0.dev468.dist-info/top_level.txt,sha256=Rbnk5d5wi58vnAXx13WFZqdQ4VX8hBCS2hEL3WeXOhY,7
381
- ommlds-0.0.0.dev468.dist-info/RECORD,,
380
+ ommlds-0.0.0.dev469.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
381
+ ommlds-0.0.0.dev469.dist-info/METADATA,sha256=DpB16y8YfJ2LGRK-RKtvFKjVZq0GVA4U1dd_eu2rUP4,3224
382
+ ommlds-0.0.0.dev469.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
383
+ ommlds-0.0.0.dev469.dist-info/entry_points.txt,sha256=Z5YWtX7ClfiCKdW-dd_CSVvM0h4yQpJPi-2G3q6gNFo,35
384
+ ommlds-0.0.0.dev469.dist-info/top_level.txt,sha256=Rbnk5d5wi58vnAXx13WFZqdQ4VX8hBCS2hEL3WeXOhY,7
385
+ ommlds-0.0.0.dev469.dist-info/RECORD,,