ommlds 0.0.0.dev504__py3-none-any.whl → 0.0.0.dev506__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.
ommlds/__about__.py CHANGED
@@ -29,7 +29,7 @@ class Project(ProjectBase):
29
29
  'tiktoken ~= 0.12',
30
30
 
31
31
  # 'tinygrad @ git+https://github.com/tinygrad/tinygrad',
32
- 'tinygrad ~= 0.11',
32
+ 'tinygrad ~= 0.12',
33
33
 
34
34
  'tokenizers ~= 0.22',
35
35
 
@@ -41,11 +41,11 @@ class Project(ProjectBase):
41
41
 
42
42
  'huggingface': [
43
43
  'huggingface-hub ~= 0.36',
44
- 'datasets ~= 4.4',
44
+ 'datasets ~= 4.5',
45
45
  ],
46
46
 
47
47
  'nanochat': [
48
- 'regex >= 2025.0',
48
+ 'regex >= 2026.1',
49
49
  ],
50
50
 
51
51
  'numpy': [
@@ -1320,7 +1320,6 @@ def _process_dataclass__2eae35290b327f0d934cd6747eeb9064b6f01259():
1320
1320
  ),
1321
1321
  cls_names=(
1322
1322
  ('ommlds.cli.main', 'InterfaceConfig'),
1323
- ('ommlds.cli.main', 'TextualInterfaceConfig'),
1324
1323
  ),
1325
1324
  )
1326
1325
  def _process_dataclass__d65d18393f357ae0fb02bb80268c6f1473462613():
@@ -1740,6 +1739,176 @@ def _process_dataclass__76648be4a999973a966584081092052c01632d85():
1740
1739
  return _process_dataclass
1741
1740
 
1742
1741
 
1742
+ @_register(
1743
+ plan_repr=(
1744
+ "Plans(tup=(CopyPlan(fields=('enable_tools', 'dangerous_no_tool_confirmation', 'input_history_file')), EqPlan(f"
1745
+ "ields=('enable_tools', 'dangerous_no_tool_confirmation', 'input_history_file')), FrozenPlan(fields=('enable_to"
1746
+ "ols', 'dangerous_no_tool_confirmation', 'input_history_file'), allow_dynamic_dunder_attrs=False), HashPlan(act"
1747
+ "ion='add', fields=('enable_tools', 'dangerous_no_tool_confirmation', 'input_history_file'), cache=False), Init"
1748
+ "Plan(fields=(InitPlan.Field(name='enable_tools', annotation=OpRef(name='init.fields.0.annotation'), default=Op"
1749
+ "Ref(name='init.fields.0.default'), default_factory=None, init=True, override=False, field_type=FieldType.INSTA"
1750
+ "NCE, coerce=None, validate=None, check_type=None), InitPlan.Field(name='dangerous_no_tool_confirmation', annot"
1751
+ "ation=OpRef(name='init.fields.1.annotation'), default=OpRef(name='init.fields.1.default'), default_factory=Non"
1752
+ "e, init=True, override=False, field_type=FieldType.INSTANCE, coerce=None, validate=None, check_type=None), Ini"
1753
+ "tPlan.Field(name='input_history_file', annotation=OpRef(name='init.fields.2.annotation'), default=OpRef(name='"
1754
+ "init.fields.2.default'), default_factory=None, init=True, override=False, field_type=FieldType.INSTANCE, coerc"
1755
+ "e=None, validate=None, check_type=None)), self_param='self', std_params=(), kw_only_params=('enable_tools', 'd"
1756
+ "angerous_no_tool_confirmation', 'input_history_file'), frozen=True, slots=False, post_init_params=None, init_f"
1757
+ "ns=(), validate_fns=()), ReprPlan(fields=(ReprPlan.Field(name='enable_tools', kw_only=True, fn=None), ReprPlan"
1758
+ ".Field(name='dangerous_no_tool_confirmation', kw_only=True, fn=None), ReprPlan.Field(name='input_history_file'"
1759
+ ", kw_only=True, fn=None)), id=False, terse=False, default_fn=None)))"
1760
+ ),
1761
+ plan_repr_sha1='f515764cf4b50b208c232c9355d9b2ed75cf26f4',
1762
+ op_ref_idents=(
1763
+ '__dataclass__init__fields__0__annotation',
1764
+ '__dataclass__init__fields__0__default',
1765
+ '__dataclass__init__fields__1__annotation',
1766
+ '__dataclass__init__fields__1__default',
1767
+ '__dataclass__init__fields__2__annotation',
1768
+ '__dataclass__init__fields__2__default',
1769
+ ),
1770
+ cls_names=(
1771
+ ('ommlds.cli.main', 'TextualInterfaceConfig'),
1772
+ ),
1773
+ )
1774
+ def _process_dataclass__f515764cf4b50b208c232c9355d9b2ed75cf26f4():
1775
+ def _process_dataclass(
1776
+ *,
1777
+ __dataclass__cls,
1778
+ __dataclass__init__fields__0__annotation,
1779
+ __dataclass__init__fields__0__default,
1780
+ __dataclass__init__fields__1__annotation,
1781
+ __dataclass__init__fields__1__default,
1782
+ __dataclass__init__fields__2__annotation,
1783
+ __dataclass__init__fields__2__default,
1784
+ __dataclass__FieldFnValidationError, # noqa
1785
+ __dataclass__FieldTypeValidationError, # noqa
1786
+ __dataclass__FnValidationError, # noqa
1787
+ __dataclass__FrozenInstanceError=dataclasses.FrozenInstanceError, # noqa
1788
+ __dataclass__FunctionType=types.FunctionType, # noqa
1789
+ __dataclass__HAS_DEFAULT_FACTORY=dataclasses._HAS_DEFAULT_FACTORY, # noqa
1790
+ __dataclass__MISSING=dataclasses.MISSING, # noqa
1791
+ __dataclass__None=None, # noqa
1792
+ __dataclass__TypeError=TypeError, # noqa
1793
+ __dataclass___recursive_repr=reprlib.recursive_repr, # noqa
1794
+ __dataclass__isinstance=isinstance, # noqa
1795
+ __dataclass__object_setattr=object.__setattr__, # noqa
1796
+ __dataclass__property=property, # noqa
1797
+ ):
1798
+ def __copy__(self):
1799
+ if self.__class__ is not __dataclass__cls:
1800
+ raise TypeError(self)
1801
+ return __dataclass__cls( # noqa
1802
+ enable_tools=self.enable_tools,
1803
+ dangerous_no_tool_confirmation=self.dangerous_no_tool_confirmation,
1804
+ input_history_file=self.input_history_file,
1805
+ )
1806
+
1807
+ __copy__.__qualname__ = f"{__dataclass__cls.__qualname__}.__copy__"
1808
+ if '__copy__' in __dataclass__cls.__dict__:
1809
+ raise __dataclass__TypeError(f"Cannot overwrite attribute __copy__ in class {__dataclass__cls.__name__}")
1810
+ setattr(__dataclass__cls, '__copy__', __copy__)
1811
+
1812
+ def __eq__(self, other):
1813
+ if self is other:
1814
+ return True
1815
+ if self.__class__ is not other.__class__:
1816
+ return NotImplemented
1817
+ return (
1818
+ self.enable_tools == other.enable_tools and
1819
+ self.dangerous_no_tool_confirmation == other.dangerous_no_tool_confirmation and
1820
+ self.input_history_file == other.input_history_file
1821
+ )
1822
+
1823
+ __eq__.__qualname__ = f"{__dataclass__cls.__qualname__}.__eq__"
1824
+ if '__eq__' in __dataclass__cls.__dict__:
1825
+ raise __dataclass__TypeError(f"Cannot overwrite attribute __eq__ in class {__dataclass__cls.__name__}")
1826
+ setattr(__dataclass__cls, '__eq__', __eq__)
1827
+
1828
+ __dataclass___setattr_frozen_fields = {
1829
+ 'enable_tools',
1830
+ 'dangerous_no_tool_confirmation',
1831
+ 'input_history_file',
1832
+ }
1833
+
1834
+ def __setattr__(self, name, value):
1835
+ if (
1836
+ type(self) is __dataclass__cls
1837
+ or name in __dataclass___setattr_frozen_fields
1838
+ ):
1839
+ raise __dataclass__FrozenInstanceError(f"cannot assign to field {name!r}")
1840
+ super(__dataclass__cls, self).__setattr__(name, value)
1841
+
1842
+ __setattr__.__qualname__ = f"{__dataclass__cls.__qualname__}.__setattr__"
1843
+ if '__setattr__' in __dataclass__cls.__dict__:
1844
+ raise __dataclass__TypeError(f"Cannot overwrite attribute __setattr__ in class {__dataclass__cls.__name__}")
1845
+ setattr(__dataclass__cls, '__setattr__', __setattr__)
1846
+
1847
+ __dataclass___delattr_frozen_fields = {
1848
+ 'enable_tools',
1849
+ 'dangerous_no_tool_confirmation',
1850
+ 'input_history_file',
1851
+ }
1852
+
1853
+ def __delattr__(self, name):
1854
+ if (
1855
+ type(self) is __dataclass__cls
1856
+ or name in __dataclass___delattr_frozen_fields
1857
+ ):
1858
+ raise __dataclass__FrozenInstanceError(f"cannot delete field {name!r}")
1859
+ super(__dataclass__cls, self).__delattr__(name)
1860
+
1861
+ __delattr__.__qualname__ = f"{__dataclass__cls.__qualname__}.__delattr__"
1862
+ if '__delattr__' in __dataclass__cls.__dict__:
1863
+ raise __dataclass__TypeError(f"Cannot overwrite attribute __delattr__ in class {__dataclass__cls.__name__}")
1864
+ setattr(__dataclass__cls, '__delattr__', __delattr__)
1865
+
1866
+ def __hash__(self):
1867
+ return hash((
1868
+ self.enable_tools,
1869
+ self.dangerous_no_tool_confirmation,
1870
+ self.input_history_file,
1871
+ ))
1872
+
1873
+ __hash__.__qualname__ = f"{__dataclass__cls.__qualname__}.__hash__"
1874
+ setattr(__dataclass__cls, '__hash__', __hash__)
1875
+
1876
+ def __init__(
1877
+ self,
1878
+ *,
1879
+ enable_tools: __dataclass__init__fields__0__annotation = __dataclass__init__fields__0__default,
1880
+ dangerous_no_tool_confirmation: __dataclass__init__fields__1__annotation = __dataclass__init__fields__1__default,
1881
+ input_history_file: __dataclass__init__fields__2__annotation = __dataclass__init__fields__2__default,
1882
+ ) -> __dataclass__None:
1883
+ __dataclass__object_setattr(self, 'enable_tools', enable_tools)
1884
+ __dataclass__object_setattr(self, 'dangerous_no_tool_confirmation', dangerous_no_tool_confirmation)
1885
+ __dataclass__object_setattr(self, 'input_history_file', input_history_file)
1886
+
1887
+ __init__.__qualname__ = f"{__dataclass__cls.__qualname__}.__init__"
1888
+ if '__init__' in __dataclass__cls.__dict__:
1889
+ raise __dataclass__TypeError(f"Cannot overwrite attribute __init__ in class {__dataclass__cls.__name__}")
1890
+ setattr(__dataclass__cls, '__init__', __init__)
1891
+
1892
+ @__dataclass___recursive_repr()
1893
+ def __repr__(self):
1894
+ parts = []
1895
+ parts.append(f"enable_tools={self.enable_tools!r}")
1896
+ parts.append(f"dangerous_no_tool_confirmation={self.dangerous_no_tool_confirmation!r}")
1897
+ parts.append(f"input_history_file={self.input_history_file!r}")
1898
+ return (
1899
+ f"{self.__class__.__qualname__}("
1900
+ f"{', '.join(parts)}"
1901
+ f")"
1902
+ )
1903
+
1904
+ __repr__.__qualname__ = f"{__dataclass__cls.__qualname__}.__repr__"
1905
+ if '__repr__' in __dataclass__cls.__dict__:
1906
+ raise __dataclass__TypeError(f"Cannot overwrite attribute __repr__ in class {__dataclass__cls.__name__}")
1907
+ setattr(__dataclass__cls, '__repr__', __repr__)
1908
+
1909
+ return _process_dataclass
1910
+
1911
+
1743
1912
  @_register(
1744
1913
  plan_repr=(
1745
1914
  "Plans(tup=(CopyPlan(fields=('enabled_tools', 'verbose')), EqPlan(fields=('enabled_tools', 'verbose')), FrozenP"
@@ -1,3 +1,8 @@
1
+ """
2
+ TODO:
3
+ - textual.getters.query_one
4
+ - AUTO_FOCUS
5
+ """
1
6
  import asyncio
2
7
  import os
3
8
  import typing as ta
@@ -15,6 +20,7 @@ from ...drivers.events.types import AiDeltaChatEvent
15
20
  from ...drivers.events.types import AiMessagesChatEvent
16
21
  from ...drivers.types import ChatDriver
17
22
  from ...facades.facade import ChatFacade
23
+ from .inputhistory import InputHistoryManager
18
24
  from .styles import read_app_css
19
25
  from .widgets.input import InputOuter
20
26
  from .widgets.input import InputTextArea
@@ -55,6 +61,7 @@ class ChatApp(tx.App):
55
61
  chat_event_queue: ChatEventQueue,
56
62
  backend_name: BackendName | None = None,
57
63
  devtools_setup: tx.DevtoolsSetup | None = None,
64
+ input_history_manager: InputHistoryManager,
58
65
  ) -> None:
59
66
  super().__init__()
60
67
 
@@ -65,6 +72,7 @@ class ChatApp(tx.App):
65
72
  self._chat_driver = chat_driver
66
73
  self._chat_event_queue = chat_event_queue
67
74
  self._backend_name = backend_name
75
+ self._input_history_manager = input_history_manager
68
76
 
69
77
  self._chat_action_queue: asyncio.Queue[ta.Any] = asyncio.Queue()
70
78
 
@@ -263,8 +271,34 @@ class ChatApp(tx.App):
263
271
  ),
264
272
  )
265
273
 
274
+ self._input_history_manager.add(event.text)
275
+
266
276
  await self._chat_action_queue.put(ChatApp.UserInput(event.text))
267
277
 
278
+ def _move_input_cursor_to_end(self) -> None:
279
+ ita = self._get_input_text_area()
280
+ ln = ita.document.line_count - 1
281
+ lt = ita.document.lines[ln]
282
+ ita.move_cursor((ln, len(lt)))
283
+
284
+ @tx.on(InputTextArea.HistoryPrevious)
285
+ async def on_input_text_area_history_previous(self, event: InputTextArea.HistoryPrevious) -> None:
286
+ if (entry := self._input_history_manager.get_previous(event.text)) is not None:
287
+ self._get_input_text_area().text = entry
288
+ self._move_input_cursor_to_end()
289
+
290
+ @tx.on(InputTextArea.HistoryNext)
291
+ async def on_input_text_area_history_next(self, event: InputTextArea.HistoryNext) -> None:
292
+ if (entry := self._input_history_manager.get_next(event.text)) is not None:
293
+ ita = self._get_input_text_area()
294
+ ita.text = entry
295
+ self._move_input_cursor_to_end()
296
+ else:
297
+ # At the end of history, clear the input
298
+ ita = self._get_input_text_area()
299
+ ita.clear()
300
+ self._input_history_manager.reset_position()
301
+
268
302
  @tx.on(tx.Key)
269
303
  async def on_key(self, event: tx.Key) -> None:
270
304
  if event in self._input_focused_key_events:
@@ -8,4 +8,4 @@ from ..configs import InterfaceConfig
8
8
 
9
9
  @dc.dataclass(frozen=True, kw_only=True)
10
10
  class TextualInterfaceConfig(InterfaceConfig):
11
- pass
11
+ input_history_file: str | None = None
@@ -20,6 +20,7 @@ with lang.auto_proxy_import(globals()):
20
20
  from ...facades import ui as _facades_ui
21
21
  from . import app as _app
22
22
  from . import facades as _facades
23
+ from . import inputhistory as _inputhistory
23
24
  from . import interface as _interface
24
25
  from . import tools as _tools
25
26
 
@@ -94,4 +95,17 @@ def bind_textual(cfg: TextualInterfaceConfig = TextualInterfaceConfig()) -> inj.
94
95
 
95
96
  #
96
97
 
98
+ def _make_input_history_storage() -> _inputhistory.InputHistoryStorage:
99
+ if cfg.input_history_file is not None:
100
+ return _inputhistory.FileInputHistoryStorage(path=cfg.input_history_file)
101
+ else:
102
+ return _inputhistory.InMemoryInputHistoryStorage()
103
+
104
+ els.extend([
105
+ inj.bind(_inputhistory.InputHistoryStorage, to_fn=_make_input_history_storage, singleton=True),
106
+ inj.bind(_inputhistory.InputHistoryManager, singleton=True),
107
+ ])
108
+
109
+ #
110
+
97
111
  return inj.as_elements(*els)
@@ -0,0 +1,174 @@
1
+ import abc
2
+ import json
3
+ import os
4
+ import typing as ta
5
+
6
+ from omlish import lang
7
+
8
+
9
+ ##
10
+
11
+
12
+ class InputHistoryStorage(lang.Abstract):
13
+ @abc.abstractmethod
14
+ def load(self) -> list[str]:
15
+ raise NotImplementedError
16
+
17
+ @abc.abstractmethod
18
+ def save(self, entries: ta.Sequence[str]) -> None:
19
+ raise NotImplementedError
20
+
21
+
22
+ class InMemoryInputHistoryStorage(InputHistoryStorage):
23
+ def __init__(self) -> None:
24
+ super().__init__()
25
+
26
+ self._entries: list[str] = []
27
+
28
+ def load(self) -> list[str]:
29
+ return list(self._entries)
30
+
31
+ def save(self, entries: ta.Sequence[str]) -> None:
32
+ self._entries = list(entries)
33
+
34
+
35
+ class FileInputHistoryStorage(InputHistoryStorage):
36
+ def __init__(self, *, path: str) -> None:
37
+ super().__init__()
38
+
39
+ self._path = path
40
+
41
+ def load(self) -> list[str]:
42
+ if not os.path.exists(self._path):
43
+ return []
44
+
45
+ try:
46
+ with open(self._path) as f:
47
+ data = json.load(f)
48
+ if isinstance(data, list) and all(isinstance(e, str) for e in data):
49
+ return data
50
+ return []
51
+ except (json.JSONDecodeError, OSError):
52
+ return []
53
+
54
+ def save(self, entries: ta.Sequence[str]) -> None:
55
+ try:
56
+ dir_path = os.path.dirname(self._path)
57
+ if dir_path:
58
+ os.makedirs(dir_path, exist_ok=True)
59
+ with open(self._path, 'w') as f:
60
+ json.dump(list(entries), f, indent=2)
61
+ except OSError:
62
+ pass
63
+
64
+
65
+ ##
66
+
67
+
68
+ class InputHistoryManager:
69
+ """
70
+ Manages input history with readline-style navigation.
71
+
72
+ History position semantics:
73
+ - Position starts at len(history) (one past the end)
74
+ - Moving 'previous' decrements position
75
+ - Moving 'next' increments position
76
+ - Position is clamped to [0, len(history)]
77
+ - Position len(history) represents 'no history item selected'
78
+ """
79
+
80
+ def __init__(
81
+ self,
82
+ *,
83
+ storage: InputHistoryStorage,
84
+ max_entries: int = 1000,
85
+ ) -> None:
86
+ super().__init__()
87
+
88
+ self._storage = storage
89
+ self._max_entries = max_entries
90
+
91
+ self._entries: list[str] = self._storage.load()
92
+ self._position: int = len(self._entries)
93
+ self._current_draft: str = ''
94
+
95
+ def add(self, text: str) -> None:
96
+ """Add a new history entry and reset position."""
97
+
98
+ if not text.strip():
99
+ return
100
+
101
+ # Don't add duplicate consecutive entries
102
+ if self._entries and self._entries[-1] == text:
103
+ self.reset_position()
104
+ return
105
+
106
+ self._entries.append(text)
107
+
108
+ # Trim to max size
109
+ if len(self._entries) > self._max_entries:
110
+ self._entries = self._entries[-self._max_entries:]
111
+
112
+ self._storage.save(self._entries)
113
+ self.reset_position()
114
+
115
+ def get_previous(self, text: str | None = None) -> str | None:
116
+ """
117
+ Navigate to previous (older) history entry.
118
+
119
+ Args:
120
+ text: Current text in the input field (saved as draft when at end of history)
121
+
122
+ Returns:
123
+ The previous history entry, or None if at the beginning
124
+ """
125
+
126
+ if not self._entries:
127
+ return None
128
+
129
+ # Save current draft if we're at the end
130
+ if self._position == len(self._entries) and text is not None:
131
+ self._current_draft = text
132
+
133
+ # Move to previous entry
134
+ if self._position > 0:
135
+ self._position -= 1
136
+ return self._entries[self._position]
137
+
138
+ # Already at oldest entry
139
+ return self._entries[0] if self._entries else None
140
+
141
+ def get_next(self, text: str | None = None) -> str | None:
142
+ """
143
+ Navigate to next (newer) history entry.
144
+
145
+ Args:
146
+ text: Current text in the input field (unused for now)
147
+
148
+ Returns:
149
+ The next history entry, the saved draft if moving past the end, or None
150
+ """
151
+
152
+ if not self._entries:
153
+ return None
154
+
155
+ # Move to next entry
156
+ if self._position < len(self._entries):
157
+ self._position += 1
158
+
159
+ # If we moved past the end, return the draft
160
+ if self._position == len(self._entries):
161
+ draft = self._current_draft
162
+ self._current_draft = ''
163
+ return draft
164
+
165
+ return self._entries[self._position]
166
+
167
+ # Already at newest position
168
+ return None
169
+
170
+ def reset_position(self) -> None:
171
+ """Reset history position to the end (no history item selected)."""
172
+
173
+ self._position = len(self._entries)
174
+ self._current_draft = ''
@@ -12,19 +12,53 @@ class InputTextArea(tx.TextArea):
12
12
  class Submitted(tx.Message):
13
13
  text: str
14
14
 
15
+ @dc.dataclass()
16
+ class HistoryPrevious(tx.Message):
17
+ text: str
18
+
19
+ @dc.dataclass()
20
+ class HistoryNext(tx.Message):
21
+ text: str
22
+
23
+ @dc.dataclass()
24
+ class HistoryReset(tx.Message):
25
+ pass
26
+
15
27
  def __init__(self, **kwargs: ta.Any) -> None:
16
28
  super().__init__(**kwargs)
17
29
 
18
- async def _on_key(self, event: tx.Key) -> None:
19
- if event.key == 'enter':
20
- event.prevent_default()
21
- event.stop()
30
+ BINDINGS: ta.ClassVar[ta.Sequence[tx.Binding]] = [ # type: ignore[assignment]
31
+ tx.Binding(
32
+ 'enter',
33
+ 'submit',
34
+ priority=True,
35
+ ),
36
+ tx.Binding(
37
+ 'ctrl+p',
38
+ 'history_previous',
39
+ ),
40
+ tx.Binding(
41
+ 'ctrl+n',
42
+ 'history_next',
43
+ ),
44
+ ]
45
+
46
+ def action_submit(self) -> None:
47
+ if text := self.text.strip():
48
+ self.post_message(self.Submitted(text))
49
+
50
+ def action_cursor_up(self, select: bool = False) -> None:
51
+ # FIXME: if empty -> history_previous
52
+ super().action_cursor_up(select=select)
53
+
54
+ def action_cursor_down(self, select: bool = False) -> None:
55
+ super().action_cursor_down(select=select)
22
56
 
23
- if text := self.text.strip():
24
- self.post_message(self.Submitted(text))
57
+ def action_history_previous(self) -> None:
58
+ self.post_message(self.HistoryPrevious(self.text))
25
59
 
26
- else:
27
- await super()._on_key(event)
60
+ def action_history_next(self) -> None:
61
+ self.post_message(self.HistoryNext(self.text))
28
62
 
29
63
 
30
64
  class InputOuter(tx.Static):
@@ -659,20 +659,22 @@ def _process_dataclass__3576262424b3ef8ff20966fa3744e5dba9a2ae7d():
659
659
  "True, override=False, field_type=FieldType.INSTANCE, coerce=None, validate=None, check_type=None)), self_param"
660
660
  "='self', std_params=(), kw_only_params=('default', 'aliases'), frozen=True, slots=False, post_init_params=None"
661
661
  ", init_fns=(), validate_fns=()), ReprPlan(fields=(ReprPlan.Field(name='default', kw_only=True, fn=None), ReprP"
662
- "lan.Field(name='aliases', kw_only=True, fn=None)), id=False, terse=False, default_fn=None)))"
662
+ "lan.Field(name='aliases', kw_only=True, fn=None)), id=False, terse=False, default_fn=OpRef(name='repr.default_"
663
+ "fn'))))"
663
664
  ),
664
- plan_repr_sha1='ac01c4fef98980477efa107b7b5909a6386bef53',
665
+ plan_repr_sha1='c8c236ef2e6c5a0fc4cdfc450a520f0cc16ee67e',
665
666
  op_ref_idents=(
666
667
  '__dataclass__init__fields__0__annotation',
667
668
  '__dataclass__init__fields__0__default',
668
669
  '__dataclass__init__fields__1__annotation',
669
670
  '__dataclass__init__fields__1__default',
671
+ '__dataclass__repr__default_fn',
670
672
  ),
671
673
  cls_names=(
672
674
  ('ommlds.minichain.backends.catalogs.strings', 'ModelNameCollection'),
673
675
  ),
674
676
  )
675
- def _process_dataclass__ac01c4fef98980477efa107b7b5909a6386bef53():
677
+ def _process_dataclass__c8c236ef2e6c5a0fc4cdfc450a520f0cc16ee67e():
676
678
  def _process_dataclass(
677
679
  *,
678
680
  __dataclass__cls,
@@ -680,6 +682,7 @@ def _process_dataclass__ac01c4fef98980477efa107b7b5909a6386bef53():
680
682
  __dataclass__init__fields__0__default,
681
683
  __dataclass__init__fields__1__annotation,
682
684
  __dataclass__init__fields__1__default,
685
+ __dataclass__repr__default_fn,
683
686
  __dataclass__FieldFnValidationError, # noqa
684
687
  __dataclass__FieldTypeValidationError, # noqa
685
688
  __dataclass__FnValidationError, # noqa
@@ -784,8 +787,10 @@ def _process_dataclass__ac01c4fef98980477efa107b7b5909a6386bef53():
784
787
  @__dataclass___recursive_repr()
785
788
  def __repr__(self):
786
789
  parts = []
787
- parts.append(f"default={self.default!r}")
788
- parts.append(f"aliases={self.aliases!r}")
790
+ if (s := __dataclass__repr__default_fn(self.default)) is not None:
791
+ parts.append(f"default={s}")
792
+ if (s := __dataclass__repr__default_fn(self.aliases)) is not None:
793
+ parts.append(f"aliases={s}")
789
794
  return (
790
795
  f"{self.__class__.__qualname__}("
791
796
  f"{', '.join(parts)}"
@@ -32,10 +32,11 @@ class BackendStringBackendCatalog(BackendCatalog):
32
32
 
33
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
- rs = check.not_none(self._string_resolver.resolve_backend_string(ResolveBackendStringArgs(
35
+ rba = ResolveBackendStringArgs(
36
36
  service_cls,
37
37
  ps,
38
- )))
38
+ )
39
+ rs = check.not_none(self._string_resolver.resolve_backend_string(rba))
39
40
 
40
41
  al: list = list(rs.args or [])
41
42
 
@@ -97,6 +97,8 @@ class ManifestBackendStringResolver(BackendStringResolver):
97
97
  for scn in manifest.service_cls_names
98
98
  }
99
99
 
100
+ __repr__ = lang.attr_ops('_manifest').repr
101
+
100
102
  def _resolve_name_model(
101
103
  self,
102
104
  args: ResolveBackendStringArgs,
@@ -6,6 +6,7 @@ import typing as ta
6
6
 
7
7
  from omlish import cached
8
8
  from omlish import dataclasses as dc
9
+ from omlish import lang
9
10
  from omlish.algorithm.toposort import mut_toposort
10
11
 
11
12
 
@@ -13,6 +14,7 @@ from omlish.algorithm.toposort import mut_toposort
13
14
 
14
15
 
15
16
  @dc.dataclass(frozen=True, kw_only=True)
17
+ @dc.extra_class_params(default_repr_fn=lang.opt_repr)
16
18
  class ModelNameCollection:
17
19
  default: str | None = None
18
20
 
@@ -1,3 +1,4 @@
1
+ # https://github.com/karpathy/rustbpe/tree/ddf848f6961a0655dc8693742fc338e5682c0d3b
1
2
  # https://github.com/karpathy/nanochat/tree/9467d83cf23dcc9a9b4ca6e35103142f48a55b27
2
3
 
3
4
  ---
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ommlds
3
- Version: 0.0.0.dev504
3
+ Version: 0.0.0.dev506
4
4
  Summary: ommlds
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -14,21 +14,21 @@ 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: omlish==0.0.0.dev504
17
+ Requires-Dist: omlish==0.0.0.dev506
18
18
  Provides-Extra: all
19
- Requires-Dist: omdev==0.0.0.dev504; extra == "all"
19
+ Requires-Dist: omdev==0.0.0.dev506; extra == "all"
20
20
  Requires-Dist: llama-cpp-python~=0.3; extra == "all"
21
21
  Requires-Dist: mlx~=0.30; sys_platform == "darwin" and extra == "all"
22
22
  Requires-Dist: mlx-lm~=0.29; sys_platform == "darwin" and extra == "all"
23
23
  Requires-Dist: tiktoken~=0.12; extra == "all"
24
- Requires-Dist: tinygrad~=0.11; extra == "all"
24
+ Requires-Dist: tinygrad~=0.12; extra == "all"
25
25
  Requires-Dist: tokenizers~=0.22; extra == "all"
26
26
  Requires-Dist: torch~=2.9; extra == "all"
27
27
  Requires-Dist: transformers~=4.57; extra == "all"
28
28
  Requires-Dist: sentence-transformers~=5.2; extra == "all"
29
29
  Requires-Dist: huggingface-hub~=0.36; extra == "all"
30
- Requires-Dist: datasets~=4.4; extra == "all"
31
- Requires-Dist: regex>=2025.0; extra == "all"
30
+ Requires-Dist: datasets~=4.5; extra == "all"
31
+ Requires-Dist: regex>=2026.1; extra == "all"
32
32
  Requires-Dist: numpy>=1.26; extra == "all"
33
33
  Requires-Dist: pytesseract~=0.3; extra == "all"
34
34
  Requires-Dist: rapidocr-onnxruntime~=1.4; extra == "all"
@@ -38,22 +38,22 @@ Requires-Dist: mwparserfromhell~=0.7; extra == "all"
38
38
  Requires-Dist: wikitextparser~=0.56; extra == "all"
39
39
  Requires-Dist: lxml>=5.3; python_version < "3.13" and extra == "all"
40
40
  Provides-Extra: omdev
41
- Requires-Dist: omdev==0.0.0.dev504; extra == "omdev"
41
+ Requires-Dist: omdev==0.0.0.dev506; extra == "omdev"
42
42
  Provides-Extra: backends
43
43
  Requires-Dist: llama-cpp-python~=0.3; extra == "backends"
44
44
  Requires-Dist: mlx~=0.30; sys_platform == "darwin" and extra == "backends"
45
45
  Requires-Dist: mlx-lm~=0.29; sys_platform == "darwin" and extra == "backends"
46
46
  Requires-Dist: tiktoken~=0.12; extra == "backends"
47
- Requires-Dist: tinygrad~=0.11; extra == "backends"
47
+ Requires-Dist: tinygrad~=0.12; extra == "backends"
48
48
  Requires-Dist: tokenizers~=0.22; extra == "backends"
49
49
  Requires-Dist: torch~=2.9; extra == "backends"
50
50
  Requires-Dist: transformers~=4.57; extra == "backends"
51
51
  Requires-Dist: sentence-transformers~=5.2; extra == "backends"
52
52
  Provides-Extra: huggingface
53
53
  Requires-Dist: huggingface-hub~=0.36; extra == "huggingface"
54
- Requires-Dist: datasets~=4.4; extra == "huggingface"
54
+ Requires-Dist: datasets~=4.5; extra == "huggingface"
55
55
  Provides-Extra: nanochat
56
- Requires-Dist: regex>=2025.0; extra == "nanochat"
56
+ Requires-Dist: regex>=2026.1; extra == "nanochat"
57
57
  Provides-Extra: numpy
58
58
  Requires-Dist: numpy>=1.26; extra == "numpy"
59
59
  Provides-Extra: ocr
@@ -1,6 +1,6 @@
1
1
  ommlds/.omlish-manifests.json,sha256=8fbwe2p3vu-qOXuBIKtwadocgl-rNP6H42qRRR_j9mY,28359
2
2
  ommlds/README.md,sha256=xhbl2n19GznXrIzAGdlX8PAYJYsOo_Zu63I7G1UFRZE,398
3
- ommlds/__about__.py,sha256=cdexoZ9J6msGQeIwveAx4JM0WlBDrWdjRkhSI9VHB9Q,1901
3
+ ommlds/__about__.py,sha256=5uwlSH3-Tf8nr0wsDL7kYqAQ_lI21WAYbTlAlGLtwyI,1901
4
4
  ommlds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  ommlds/_hacks/__init__.py,sha256=ajfw7dMKH8UuloeQ5MSxWwgAmdWf2v8gm-K3uLP9wtY,196
6
6
  ommlds/_hacks/funcs.py,sha256=8XseIblP7yolDUD7WQSGn1LP90IQzByVejSzphAPDyM,2861
@@ -102,7 +102,7 @@ ommlds/backends/transformers/filecache.py,sha256=ycfswt7f4qRrPSTFRhofXZaDBuDPpyp
102
102
  ommlds/backends/transformers/streamers.py,sha256=Hu_9lp_kUilKjOfs7Ixqr2NoA5FuRn2eRh8JdvaBDYc,1688
103
103
  ommlds/cli/__init__.py,sha256=-RtLrdEGN2da1KCf7YNs32jN-kJhT_kNVrcOv4x_J-w,101
104
104
  ommlds/cli/__main__.py,sha256=1ffCb0fcUOJMzxROJmJRXQ8PSOVYv7KrcuBtT95cf0c,140
105
- ommlds/cli/_dataclasses.py,sha256=qUx7WaHCYwvjZ5_jQjAr_EZ0Pouk5AjQG0HnisxZCEw,164764
105
+ ommlds/cli/_dataclasses.py,sha256=ewUQSDXLkba0isAcUPxInyVBPfyfWIdHR5gg0mSeCWg,173523
106
106
  ommlds/cli/asyncs.py,sha256=NAMzzaZq7ORjlbbBB_Y9vcM9qoBpGf4VJNtl_3p_8G4,629
107
107
  ommlds/cli/inject.py,sha256=Bt-T-vQIbp8vh6q21Tt3wDztFZ9FPxNhH2ocrAfjArE,815
108
108
  ommlds/cli/main.py,sha256=n_13EimSCt2x9wkn4tULk9gNOvuCHuHeDcuEYtrcUgQ,11172
@@ -210,10 +210,11 @@ ommlds/cli/sessions/chat/interfaces/bare/interactive.py,sha256=ZnYoePvXtUbhkDQ0j
210
210
  ommlds/cli/sessions/chat/interfaces/bare/oneshot.py,sha256=b758OIa0gf9I_0UdxYJ6re-g8-8xndgr3R0OotUOsmc,387
211
211
  ommlds/cli/sessions/chat/interfaces/bare/tools.py,sha256=_UsuoXLIvfpFP_We5DBBlhm6rwB3_cFA3lmFvpG9b-A,824
212
212
  ommlds/cli/sessions/chat/interfaces/textual/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
213
- ommlds/cli/sessions/chat/interfaces/textual/app.py,sha256=wEkibpKaT00J5awBHCtEwAdM00jO5yWjkul_2I6b6y0,9124
214
- ommlds/cli/sessions/chat/interfaces/textual/configs.py,sha256=HD8DlWXYJ1M94gr5TIT6oqsFCmOf5Gd6KkSBZUtySew,180
213
+ ommlds/cli/sessions/chat/interfaces/textual/app.py,sha256=NOYQPJH3IOT6mQRpjhmAWdG4V_VcMjHFivCXmYrlthE,10468
214
+ ommlds/cli/sessions/chat/interfaces/textual/configs.py,sha256=-pvG2_Uai70ohDfK4Tt8yaHnvdCs10_gaoQkr-CsOqA,213
215
215
  ommlds/cli/sessions/chat/interfaces/textual/facades.py,sha256=zXVG7DKVl-Xtdc893O_yktHCMvM0do6hLesMd8hbqeo,411
216
- ommlds/cli/sessions/chat/interfaces/textual/inject.py,sha256=ZVG-q3w1xuaIIxm35Zs9R3NyyAdbQUpQD9QXQ-1PypE,2516
216
+ ommlds/cli/sessions/chat/interfaces/textual/inject.py,sha256=eBhFVZ2VmQdoTPSZvi2OSkZ-fX8Mw2TKo28bHZeACJY,3056
217
+ ommlds/cli/sessions/chat/interfaces/textual/inputhistory.py,sha256=Jdmwd6RTBLK8rGyz4w560cwuK6LXi_OTubVfw_-ORTM,4687
217
218
  ommlds/cli/sessions/chat/interfaces/textual/interface.py,sha256=lHeuiMtA7DW9knuapZEOZSl9-9SmOfUxiPnd4-plLHE,445
218
219
  ommlds/cli/sessions/chat/interfaces/textual/tools.py,sha256=KVlUmIyzqUuOHMzB9ZXGUaGsb-Tp5LAmMpB1agAHYjo,985
219
220
  ommlds/cli/sessions/chat/interfaces/textual/styles/__init__.py,sha256=7_U5oUjwegOymeWgt6nLpFfWfjGTrlWL8m4Au8MsaFE,542
@@ -221,7 +222,7 @@ ommlds/cli/sessions/chat/interfaces/textual/styles/input.tcss,sha256=9LLwsuYjY8y
221
222
  ommlds/cli/sessions/chat/interfaces/textual/styles/markdown.tcss,sha256=KCKlgt_EEjHVZSTwP_w2YMrR6mURLYVryOwOziAFlTw,105
222
223
  ommlds/cli/sessions/chat/interfaces/textual/styles/messages.tcss,sha256=QBpHJkBT76OkT8srUwhZOt0ZT5ZCzXuM4l8P9hP9ALw,1665
223
224
  ommlds/cli/sessions/chat/interfaces/textual/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
224
- ommlds/cli/sessions/chat/interfaces/textual/widgets/input.py,sha256=7PrKv6ZqPoDOTOE2V-Pz2hru1n1Dwz_4Fxc1eBwqdr0,944
225
+ ommlds/cli/sessions/chat/interfaces/textual/widgets/input.py,sha256=MMONcOi3Aq8ZzmvJn6tHNPbfV3EOol25fABxtW1h--E,1827
225
226
  ommlds/cli/sessions/chat/interfaces/textual/widgets/messages.py,sha256=hZcentzdznaE_YPId1KsW4k8mAqsSu5zwMdTA5tIj5s,5472
226
227
  ommlds/cli/sessions/completion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
227
228
  ommlds/cli/sessions/completion/configs.py,sha256=jOtadH46Esx6CztbQazAgIx9Tt5uuu4pGPov3G3O5Ac,286
@@ -238,7 +239,7 @@ ommlds/datasets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
238
239
  ommlds/datasets/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
239
240
  ommlds/datasets/lib/movies.py,sha256=LmdfoXsZU9XMM_r-sxCLv_s06BFzwWO4xUj6sc9XVcI,1961
240
241
  ommlds/minichain/__init__.py,sha256=GryYNuSiSv7LvoIyP6rYGDnHe2Q4Rkr4majHaEd2nhs,13794
241
- ommlds/minichain/_dataclasses.py,sha256=F-kqXtzODV1RbcjR3LpTwLWqbj4CU872AhFdXECbVos,948452
242
+ ommlds/minichain/_dataclasses.py,sha256=HK9ZIQGoERkR6kZramRLHRiWBDmetTV3Rgi5J-gl5Nw,948708
242
243
  ommlds/minichain/_marshal.py,sha256=n9PGWrHhvAmGIc7KDOYt3IF9Z6G0ncXskyICTp3Ji6k,1923
243
244
  ommlds/minichain/_typedvalues.py,sha256=NEQ7YCD7YtYJoEKHRwBksHFv-CULvyXniju_IeVfD5s,2349
244
245
  ommlds/minichain/completion.py,sha256=lQ0LfCIYZsvDqteHhhDIv16D2_gn_xMfEL0ouywE5Yo,1033
@@ -255,7 +256,7 @@ ommlds/minichain/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
255
256
  ommlds/minichain/backends/catalogs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
256
257
  ommlds/minichain/backends/catalogs/base.py,sha256=6ThxF-OozMm0aGHAo3UyKUcNA3TVda0w_QLpbz7XmEU,1306
257
258
  ommlds/minichain/backends/catalogs/simple.py,sha256=T6GeY902XPRjNnwX1AivunpkirLyxFg5rG2V2LA0Puo,1501
258
- ommlds/minichain/backends/catalogs/strings.py,sha256=tuezU7px8-Jjtil0-z-LCxYt7kFolilCEU7tM68MdyQ,1822
259
+ ommlds/minichain/backends/catalogs/strings.py,sha256=e7Q8cnatOzcnhJ5zKqVkwvVjGhA8EmMg0WtqNxS61Mk,1840
259
260
  ommlds/minichain/backends/impls/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
260
261
  ommlds/minichain/backends/impls/mistral.py,sha256=nC0aqabg-I7JJyxHHMZASASksqV1at7nJWZHGtCwfio,2843
261
262
  ommlds/minichain/backends/impls/sqlite.py,sha256=NOFm_fgr-OZ8mo7etj0zwvxsDnidRwKzhdDom58e6ks,2157
@@ -319,7 +320,7 @@ ommlds/minichain/backends/impls/transformers/transformers.py,sha256=hXWNe2knROuT
319
320
  ommlds/minichain/backends/strings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
320
321
  ommlds/minichain/backends/strings/manifests.py,sha256=kmlanVUAZqIh0P95Mm8H20e8ib3gEgYHHUlkCXDQGFk,413
321
322
  ommlds/minichain/backends/strings/parsing.py,sha256=Etmk04BnKvCMtGg4AgbvxsPGvfRcLldLxpdpxcozdNk,1779
322
- ommlds/minichain/backends/strings/resolving.py,sha256=b2Ivt6Xi50Jv8U7ef6CkMWzJDTBF28pqyNN4_9z39TY,5861
323
+ ommlds/minichain/backends/strings/resolving.py,sha256=EXgOmcBJsBnUmo1FMgd3-RLR5TgNXOY27gGTN7JP01E,5909
323
324
  ommlds/minichain/chat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
324
325
  ommlds/minichain/chat/_marshal.py,sha256=M3p093nxzxITbznc--P-tyCXuWDHrq4JFKTZAx6XWdk,740
325
326
  ommlds/minichain/chat/content.py,sha256=NpxeYxP7WOWq94UR9AY0THVRIzWAcgP1w7r_srgntOk,1098
@@ -423,7 +424,7 @@ ommlds/minichain/llms/tokens.py,sha256=RPrAzf4Qx9xNPGj7_EkzcVOR9qIGkhQg8AM6qhr7g
423
424
  ommlds/minichain/llms/types.py,sha256=STXV-zAhJ2yytbVn6JSNxCLDIqmKpsg0q4vq8ueRvJA,1130
424
425
  ommlds/minichain/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
425
426
  ommlds/minichain/models/configs.py,sha256=5iyz_yDk3nlfQouRTvy__8I_ohn7bh67LTbFn30t5UU,825
426
- ommlds/minichain/models/names.py,sha256=SqXrOkSFTI2VkfA5puGGb0EFg2TvvNZpJgTF7eS60CY,1158
427
+ ommlds/minichain/models/names.py,sha256=hwzKtRMY3Ch4gBtIVfWKvlq77EQSvdPub0TZ9F3i7pM,1236
427
428
  ommlds/minichain/models/repos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
428
429
  ommlds/minichain/models/repos/resolving.py,sha256=I8l8osTJNE0mT5nmb7tYhOfNH0f-F3JQVkvIrjLPvOE,602
429
430
  ommlds/minichain/registries/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -488,7 +489,7 @@ ommlds/nanochat/LICENSE,sha256=QrsJ8zmor4uQ07SWm29uS6Sv87XGFBA7Ax_M33HI93I,1072
488
489
  ommlds/nanochat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
489
490
  ommlds/nanochat/tokenizers.py,sha256=DuDLJAawl_BuwTO1Jj8ANDkqwMFh6jkV9IPjj9DMhfA,17575
490
491
  ommlds/nanochat/rustbpe/LICENSE,sha256=QrsJ8zmor4uQ07SWm29uS6Sv87XGFBA7Ax_M33HI93I,1072
491
- ommlds/nanochat/rustbpe/README.md,sha256=JG_u4gU2Yb5e4vqdf_4SWUgj82RRCygomC1vh4bBFDY,1245
492
+ ommlds/nanochat/rustbpe/README.md,sha256=Kfa8JWWSVx4YBxjt8648fd7oMvXlsU332Z7Fx0yvWdc,1329
492
493
  ommlds/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
493
494
  ommlds/server/__main__.py,sha256=morlItVl-0_MDK6xk2VKhqOtA8oQk0SoWOWEqcgqXTw,155
494
495
  ommlds/server/cli.py,sha256=gCN__45IXjCtk-tWwO2hr8vs5K-R0e1auNWdIc7d6_U,1825
@@ -515,9 +516,9 @@ ommlds/wiki/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
515
516
  ommlds/wiki/utils/io.py,sha256=UKgDJGtmpnWvIqVd2mJc2QNPOqlToEY1GEveNp6_pMo,7088
516
517
  ommlds/wiki/utils/progress.py,sha256=EhvKcMFYtsarCQhIahlO6f0SboyAKP3UwUyrnVnP-Vk,3222
517
518
  ommlds/wiki/utils/xml.py,sha256=sNJNkZ9rT8B-kJMO6bRz8J1USy4fyPx0m2PwTX7vxYY,3846
518
- ommlds-0.0.0.dev504.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
519
- ommlds-0.0.0.dev504.dist-info/METADATA,sha256=27dO2cQB4Y10EcKB2ZammM2Ctk9TuRKiZgfIEz7MbaA,3495
520
- ommlds-0.0.0.dev504.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
521
- ommlds-0.0.0.dev504.dist-info/entry_points.txt,sha256=Z5YWtX7ClfiCKdW-dd_CSVvM0h4yQpJPi-2G3q6gNFo,35
522
- ommlds-0.0.0.dev504.dist-info/top_level.txt,sha256=Rbnk5d5wi58vnAXx13WFZqdQ4VX8hBCS2hEL3WeXOhY,7
523
- ommlds-0.0.0.dev504.dist-info/RECORD,,
519
+ ommlds-0.0.0.dev506.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
520
+ ommlds-0.0.0.dev506.dist-info/METADATA,sha256=3ncoVk1_7XcnFOZJPLu0u8dyy_wJLWhCnbObf9nnWCc,3495
521
+ ommlds-0.0.0.dev506.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
522
+ ommlds-0.0.0.dev506.dist-info/entry_points.txt,sha256=Z5YWtX7ClfiCKdW-dd_CSVvM0h4yQpJPi-2G3q6gNFo,35
523
+ ommlds-0.0.0.dev506.dist-info/top_level.txt,sha256=Rbnk5d5wi58vnAXx13WFZqdQ4VX8hBCS2hEL3WeXOhY,7
524
+ ommlds-0.0.0.dev506.dist-info/RECORD,,