ommlds 0.0.0.dev513__py3-none-any.whl → 0.0.0.dev515__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.
@@ -59,6 +59,12 @@ class ChatAppScreen(tx.Screen):
59
59
  'Copy selected text',
60
60
  show=False,
61
61
  ),
62
+
63
+ tx.Binding(
64
+ 'f10',
65
+ 'app.confirm_all_pending_tool_uses',
66
+ 'Confirms all pending tool uses',
67
+ ),
62
68
  ]
63
69
 
64
70
  @classmethod
@@ -110,6 +116,8 @@ class ChatApp(
110
116
 
111
117
  self._input_focused_key_events: weakref.WeakSet[tx.Key] = weakref.WeakSet()
112
118
 
119
+ self._pending_tool_confirmations: set[ToolConfirmationMessage] = set()
120
+
113
121
  def get_driver_class(self) -> type[tx.Driver]:
114
122
  return tx.get_pending_writes_driver_class(super().get_driver_class())
115
123
 
@@ -327,7 +335,7 @@ class ChatApp(
327
335
 
328
336
  async def on_unmount(self) -> None:
329
337
  if (cat := self._chat_action_queue_task) is not None:
330
- await self._chat_event_queue.put(None)
338
+ await self._chat_action_queue.put(None)
331
339
  await cat
332
340
 
333
341
  await self._chat_driver.stop()
@@ -351,7 +359,7 @@ class ChatApp(
351
359
  ),
352
360
  )
353
361
 
354
- self._input_history_manager.add(event.text)
362
+ await self._input_history_manager.add(event.text)
355
363
 
356
364
  await self._chat_action_queue.put(ChatApp.UserInput(event.text))
357
365
 
@@ -363,12 +371,14 @@ class ChatApp(
363
371
 
364
372
  @tx.on(InputTextArea.HistoryPrevious)
365
373
  async def on_input_text_area_history_previous(self, event: InputTextArea.HistoryPrevious) -> None:
374
+ await self._input_history_manager.load_if_necessary()
366
375
  if (entry := self._input_history_manager.get_previous(event.text)) is not None:
367
376
  self._get_input_text_area().text = entry
368
377
  self._move_input_cursor_to_end()
369
378
 
370
379
  @tx.on(InputTextArea.HistoryNext)
371
380
  async def on_input_text_area_history_next(self, event: InputTextArea.HistoryNext) -> None:
381
+ await self._input_history_manager.load_if_necessary()
372
382
  if (entry := self._input_history_manager.get_next(event.text)) is not None:
373
383
  ita = self._get_input_text_area()
374
384
  ita.text = entry
@@ -409,6 +419,10 @@ class ChatApp(
409
419
  fut,
410
420
  )
411
421
 
422
+ fut.add_done_callback(lambda _: self._pending_tool_confirmations.discard(tcm))
423
+
424
+ self._pending_tool_confirmations.add(tcm)
425
+
412
426
  async def inner() -> None:
413
427
  await self._mount_messages(tcm)
414
428
 
@@ -427,3 +441,13 @@ class ChatApp(
427
441
  async def action_cancel(self) -> None:
428
442
  if (cat := self._cur_chat_action) is not None:
429
443
  cat.cancel()
444
+
445
+ async def action_confirm_all_pending_tool_uses(self) -> None:
446
+ for tcm in list(self._pending_tool_confirmations):
447
+ if not tcm.has_rendered:
448
+ continue
449
+
450
+ if not tcm.has_confirmed:
451
+ await tcm.confirm()
452
+
453
+ self._pending_tool_confirmations.discard(tcm)
@@ -1,9 +1,9 @@
1
1
  import abc
2
- import json
3
2
  import os
4
3
  import typing as ta
5
4
 
6
5
  from omlish import lang
6
+ from omlish.formats import json
7
7
 
8
8
 
9
9
  ##
@@ -11,11 +11,11 @@ from omlish import lang
11
11
 
12
12
  class InputHistoryStorage(lang.Abstract):
13
13
  @abc.abstractmethod
14
- def load(self) -> list[str]:
14
+ def load(self) -> ta.Awaitable[list[str]]:
15
15
  raise NotImplementedError
16
16
 
17
17
  @abc.abstractmethod
18
- def save(self, entries: ta.Sequence[str]) -> None:
18
+ def save(self, entries: ta.Sequence[str]) -> ta.Awaitable[None]:
19
19
  raise NotImplementedError
20
20
 
21
21
 
@@ -25,10 +25,10 @@ class InMemoryInputHistoryStorage(InputHistoryStorage):
25
25
 
26
26
  self._entries: list[str] = []
27
27
 
28
- def load(self) -> list[str]:
28
+ async def load(self) -> list[str]:
29
29
  return list(self._entries)
30
30
 
31
- def save(self, entries: ta.Sequence[str]) -> None:
31
+ async def save(self, entries: ta.Sequence[str]) -> None:
32
32
  self._entries = list(entries)
33
33
 
34
34
 
@@ -38,26 +38,31 @@ class FileInputHistoryStorage(InputHistoryStorage):
38
38
 
39
39
  self._path = path
40
40
 
41
- def load(self) -> list[str]:
41
+ async def load(self) -> list[str]:
42
42
  if not os.path.exists(self._path):
43
43
  return []
44
44
 
45
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):
46
+ with open(self._path) as f: # noqa
47
+ content = f.read()
48
+ except OSError:
52
49
  return []
53
50
 
54
- def save(self, entries: ta.Sequence[str]) -> None:
51
+ data = json.loads(content)
52
+
53
+ if isinstance(data, list) and all(isinstance(e, str) for e in data):
54
+ return data
55
+ return []
56
+
57
+ async def save(self, entries: ta.Sequence[str]) -> None:
58
+ content = json.dumps_pretty(list(entries))
59
+ dir_path = os.path.dirname(self._path)
60
+
55
61
  try:
56
- dir_path = os.path.dirname(self._path)
57
62
  if dir_path:
58
63
  os.makedirs(dir_path, exist_ok=True)
59
- with open(self._path, 'w') as f:
60
- json.dump(list(entries), f, indent=2)
64
+ with open(self._path, 'w') as f: # noqa
65
+ f.write(content)
61
66
  except OSError:
62
67
  pass
63
68
 
@@ -88,16 +93,34 @@ class InputHistoryManager:
88
93
  self._storage = storage
89
94
  self._max_entries = max_entries
90
95
 
91
- self._entries: list[str] = self._storage.load()
92
- self._position: int = len(self._entries)
93
- self._current_draft: str = ''
96
+ #
97
+
98
+ _entries: list[str]
99
+ _position: int = 0
100
+
101
+ async def load_if_necessary(self) -> None:
102
+ try:
103
+ self._entries # noqa
104
+ except AttributeError:
105
+ pass
106
+ else:
107
+ return
108
+
109
+ self._entries = await self._storage.load()
110
+ self._position = len(self._entries)
94
111
 
95
- def add(self, text: str) -> None:
112
+ #
113
+
114
+ _current_draft: str = ''
115
+
116
+ async def add(self, text: str) -> None:
96
117
  """Add a new history entry and reset position."""
97
118
 
98
119
  if not text.strip():
99
120
  return
100
121
 
122
+ await self.load_if_necessary()
123
+
101
124
  # Don't add duplicate consecutive entries
102
125
  if self._entries and self._entries[-1] == text:
103
126
  self.reset_position()
@@ -109,7 +132,7 @@ class InputHistoryManager:
109
132
  if len(self._entries) > self._max_entries:
110
133
  self._entries = self._entries[-self._max_entries:]
111
134
 
112
- self._storage.save(self._entries)
135
+ await self._storage.save(self._entries)
113
136
  self.reset_position()
114
137
 
115
138
  def get_previous(self, text: str | None = None) -> str | None:
@@ -123,20 +146,24 @@ class InputHistoryManager:
123
146
  The previous history entry, or None if at the beginning
124
147
  """
125
148
 
126
- if not self._entries:
149
+ try:
150
+ entries = self._entries
151
+ except AttributeError:
152
+ return None
153
+ if entries:
127
154
  return None
128
155
 
129
156
  # Save current draft if we're at the end
130
- if self._position == len(self._entries) and text is not None:
157
+ if self._position == len(entries) and text is not None:
131
158
  self._current_draft = text
132
159
 
133
160
  # Move to previous entry
134
161
  if self._position > 0:
135
162
  self._position -= 1
136
- return self._entries[self._position]
163
+ return entries[self._position]
137
164
 
138
165
  # Already at oldest entry
139
- return self._entries[0] if self._entries else None
166
+ return entries[0] if entries else None
140
167
 
141
168
  def get_next(self, text: str | None = None) -> str | None:
142
169
  """
@@ -149,20 +176,24 @@ class InputHistoryManager:
149
176
  The next history entry, the saved draft if moving past the end, or None
150
177
  """
151
178
 
152
- if not self._entries:
179
+ try:
180
+ entries = self._entries
181
+ except AttributeError:
182
+ return None
183
+ if entries:
153
184
  return None
154
185
 
155
186
  # Move to next entry
156
- if self._position < len(self._entries):
187
+ if self._position < len(entries):
157
188
  self._position += 1
158
189
 
159
190
  # If we moved past the end, return the draft
160
- if self._position == len(self._entries):
191
+ if self._position == len(entries):
161
192
  draft = self._current_draft
162
193
  self._current_draft = ''
163
194
  return draft
164
195
 
165
- return self._entries[self._position]
196
+ return entries[self._position]
166
197
 
167
198
  # Already at newest position
168
199
  return None
@@ -170,5 +201,11 @@ class InputHistoryManager:
170
201
  def reset_position(self) -> None:
171
202
  """Reset history position to the end (no history item selected)."""
172
203
 
173
- self._position = len(self._entries)
204
+ try:
205
+ entries = self._entries
206
+ except AttributeError:
207
+ self._position = 0
208
+ else:
209
+ self._position = len(entries)
210
+
174
211
  self._current_draft = ''
@@ -3,6 +3,7 @@ import asyncio
3
3
  import typing as ta
4
4
 
5
5
  from omdev.tui import textual as tx
6
+ from omlish import check
6
7
  from omlish import lang
7
8
 
8
9
 
@@ -145,14 +146,14 @@ class StreamAiMessage(AiMessage):
145
146
 
146
147
 
147
148
  class ToolConfirmationControls(tx.Static):
148
- class Allowed(tx.Message):
149
+ class ClickedAllow(tx.Message):
149
150
  pass
150
151
 
151
152
  def compose(self) -> tx.ComposeResult:
152
153
  yield tx.Button('Allow', action='allow')
153
154
 
154
155
  def action_allow(self) -> None:
155
- self.post_message(self.Allowed())
156
+ self.post_message(self.ClickedAllow())
156
157
 
157
158
 
158
159
  class ToolConfirmationMessage(Message):
@@ -170,24 +171,58 @@ class ToolConfirmationMessage(Message):
170
171
  self._inner_content = inner_content
171
172
  self._fut = fut
172
173
 
173
- def compose(self) -> tx.ComposeResult:
174
- with tx.Horizontal(classes='tool-confirmation-message-outer message-outer'):
175
- yield tx.Static('? ', classes='tool-confirmation-message-glyph message-glyph')
176
- with tx.Vertical(classes='tool-confirmation-message-inner tool-confirmation-message-inner-open message-inner'): # noqa
177
- yield tx.Static(self._outer_content, classes='tool-confirmation-message-outer-content')
178
- yield tx.Static(self._inner_content, classes='tool-confirmation-message-inner-content')
179
- yield ToolConfirmationControls(classes='tool-confirmation-message-controls')
174
+ self._has_rendered = False
175
+ self._has_confirmed = False
176
+
177
+ @property
178
+ def has_rendered(self) -> bool:
179
+ return self._has_rendered
180
+
181
+ @property
182
+ def has_confirmed(self) -> bool:
183
+ return self._has_confirmed
184
+
185
+ async def confirm(self) -> None:
186
+ check.equal(self._fut.done(), self._has_confirmed)
187
+
188
+ if self._has_confirmed:
189
+ return
190
+ self._has_confirmed = True
180
191
 
181
- @tx.on(ToolConfirmationControls.Allowed)
182
- async def on_allowed(self, event: ToolConfirmationControls.Allowed) -> None:
183
192
  inner = self.query_one(tx.Vertical)
193
+
184
194
  await inner.query_one(ToolConfirmationControls).remove()
195
+
185
196
  inner.remove_class('tool-confirmation-message-inner-open')
186
197
  inner.add_class('tool-confirmation-message-inner-closed')
198
+
187
199
  inner.query_one('.tool-confirmation-message-outer-content', tx.Static).update('Tool use confirmed.')
188
200
 
189
201
  self._fut.set_result(True)
190
202
 
203
+ def compose(self) -> tx.ComposeResult:
204
+ with tx.Horizontal(classes='tool-confirmation-message-outer message-outer'):
205
+ yield tx.Static('? ', classes='tool-confirmation-message-glyph message-glyph')
206
+ with tx.Vertical(classes=' '.join([
207
+ 'tool-confirmation-message-inner',
208
+ 'tool-confirmation-message-inner-open',
209
+ 'message-inner',
210
+ ])):
211
+ yield tx.Static(self._outer_content, classes='tool-confirmation-message-outer-content')
212
+ yield tx.Static(self._inner_content, classes='tool-confirmation-message-inner-content')
213
+
214
+ yield ToolConfirmationControls(classes='tool-confirmation-message-controls')
215
+
216
+ def on_mount(self) -> None:
217
+ def inner():
218
+ self._has_rendered = True
219
+
220
+ self.call_after_refresh(inner)
221
+
222
+ @tx.on(ToolConfirmationControls.ClickedAllow)
223
+ async def on_clicked_allow(self, event: ToolConfirmationControls.ClickedAllow) -> None:
224
+ await self.confirm()
225
+
191
226
 
192
227
  #
193
228
 
@@ -10,7 +10,7 @@ import typing as ta
10
10
  from omlish import check
11
11
  from omlish import lang
12
12
  from omlish import typedvalues as tv
13
- from omlish.asyncs.asyncio.sync import AsyncioBufferRelay
13
+ from omlish.asyncs.asyncio.sync import AsyncioSyncBufferRelay
14
14
 
15
15
  from ....chat.choices.services import ChatChoicesRequest
16
16
  from ....chat.choices.services import ChatChoicesResponse
@@ -242,7 +242,7 @@ class TransformersChatChoicesStreamService(BaseTransformersChatChoicesService):
242
242
  for m in request.v
243
243
  ]
244
244
 
245
- relay: AsyncioBufferRelay = AsyncioBufferRelay()
245
+ relay: AsyncioSyncBufferRelay = AsyncioSyncBufferRelay()
246
246
 
247
247
  def streamer_callback(text: str, *, stream_end: bool) -> None:
248
248
  if text or stream_end:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ommlds
3
- Version: 0.0.0.dev513
3
+ Version: 0.0.0.dev515
4
4
  Summary: ommlds
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -14,9 +14,9 @@ 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.dev513
17
+ Requires-Dist: omlish==0.0.0.dev515
18
18
  Provides-Extra: all
19
- Requires-Dist: omdev==0.0.0.dev513; extra == "all"
19
+ Requires-Dist: omdev==0.0.0.dev515; 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"
@@ -39,7 +39,7 @@ Requires-Dist: mwparserfromhell~=0.7; extra == "all"
39
39
  Requires-Dist: wikitextparser~=0.56; extra == "all"
40
40
  Requires-Dist: lxml>=5.3; python_version < "3.13" and extra == "all"
41
41
  Provides-Extra: omdev
42
- Requires-Dist: omdev==0.0.0.dev513; extra == "omdev"
42
+ Requires-Dist: omdev==0.0.0.dev515; extra == "omdev"
43
43
  Provides-Extra: backends
44
44
  Requires-Dist: llama-cpp-python~=0.3; extra == "backends"
45
45
  Requires-Dist: mlx~=0.30; sys_platform == "darwin" and extra == "backends"
@@ -214,11 +214,11 @@ ommlds/cli/sessions/chat/interfaces/bare/interactive.py,sha256=ZnYoePvXtUbhkDQ0j
214
214
  ommlds/cli/sessions/chat/interfaces/bare/oneshot.py,sha256=b758OIa0gf9I_0UdxYJ6re-g8-8xndgr3R0OotUOsmc,387
215
215
  ommlds/cli/sessions/chat/interfaces/bare/tools.py,sha256=_UsuoXLIvfpFP_We5DBBlhm6rwB3_cFA3lmFvpG9b-A,824
216
216
  ommlds/cli/sessions/chat/interfaces/textual/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
217
- ommlds/cli/sessions/chat/interfaces/textual/app.py,sha256=glO32FiPn4T1nLXBOe2QpTwkFv0yGKchGZQHGFQVaOw,12614
217
+ ommlds/cli/sessions/chat/interfaces/textual/app.py,sha256=QVLD4ZT4-SJ4UQhKSfm6MAjOtqeLtYhW3tMMXxg7h88,13432
218
218
  ommlds/cli/sessions/chat/interfaces/textual/configs.py,sha256=-pvG2_Uai70ohDfK4Tt8yaHnvdCs10_gaoQkr-CsOqA,213
219
219
  ommlds/cli/sessions/chat/interfaces/textual/facades.py,sha256=zXVG7DKVl-Xtdc893O_yktHCMvM0do6hLesMd8hbqeo,411
220
220
  ommlds/cli/sessions/chat/interfaces/textual/inject.py,sha256=eBhFVZ2VmQdoTPSZvi2OSkZ-fX8Mw2TKo28bHZeACJY,3056
221
- ommlds/cli/sessions/chat/interfaces/textual/inputhistory.py,sha256=Jdmwd6RTBLK8rGyz4w560cwuK6LXi_OTubVfw_-ORTM,4687
221
+ ommlds/cli/sessions/chat/interfaces/textual/inputhistory.py,sha256=hUGrIpSmI0wlg0jwqdT42hLkrzeQF4wnN6wdom9HDJU,5332
222
222
  ommlds/cli/sessions/chat/interfaces/textual/interface.py,sha256=lHeuiMtA7DW9knuapZEOZSl9-9SmOfUxiPnd4-plLHE,445
223
223
  ommlds/cli/sessions/chat/interfaces/textual/tools.py,sha256=KVlUmIyzqUuOHMzB9ZXGUaGsb-Tp5LAmMpB1agAHYjo,985
224
224
  ommlds/cli/sessions/chat/interfaces/textual/styles/__init__.py,sha256=7_U5oUjwegOymeWgt6nLpFfWfjGTrlWL8m4Au8MsaFE,542
@@ -227,7 +227,7 @@ ommlds/cli/sessions/chat/interfaces/textual/styles/markdown.tcss,sha256=KCKlgt_E
227
227
  ommlds/cli/sessions/chat/interfaces/textual/styles/messages.tcss,sha256=tl0ZPnYY3jsumj_Y_AFaA1Vbz7AvgWC7xMuS-JOAPEk,1820
228
228
  ommlds/cli/sessions/chat/interfaces/textual/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
229
229
  ommlds/cli/sessions/chat/interfaces/textual/widgets/input.py,sha256=MMONcOi3Aq8ZzmvJn6tHNPbfV3EOol25fABxtW1h--E,1827
230
- ommlds/cli/sessions/chat/interfaces/textual/widgets/messages.py,sha256=_xu24596FT0MZMWOdE0-2SkPF_na_J6lG35CstKCI94,5614
230
+ ommlds/cli/sessions/chat/interfaces/textual/widgets/messages.py,sha256=RiERDoNe7HwSbQx0ATh0cToGhwOXnNLdnkVZnWV203g,6332
231
231
  ommlds/cli/sessions/completion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
232
232
  ommlds/cli/sessions/completion/configs.py,sha256=jOtadH46Esx6CztbQazAgIx9Tt5uuu4pGPov3G3O5Ac,286
233
233
  ommlds/cli/sessions/completion/inject.py,sha256=oWRS2D4d-mdCwi7jT_Is462k1UBlCruz4nrUeT9xedY,848
@@ -320,7 +320,7 @@ ommlds/minichain/backends/impls/tokenizers/tokens.py,sha256=wLz9UTWhHrrJm56ZSLZD
320
320
  ommlds/minichain/backends/impls/transformers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
321
321
  ommlds/minichain/backends/impls/transformers/sentence.py,sha256=0T01aY0rVauw--AdchroNkcwaK3ku0ZdP8ikcsYeHyA,1462
322
322
  ommlds/minichain/backends/impls/transformers/tokens.py,sha256=ozlTX0c3sixgcgz87OwEBoVxTF69MTz46LbHzuS8r2Y,2166
323
- ommlds/minichain/backends/impls/transformers/transformers.py,sha256=hXWNe2knROuTJoI737t5FIqUdhmldpHW89tBkfpyofM,9052
323
+ ommlds/minichain/backends/impls/transformers/transformers.py,sha256=6eQa95I4PEcUap3bhpRujEDRsVG3MX768bZk4944fPg,9064
324
324
  ommlds/minichain/backends/strings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
325
325
  ommlds/minichain/backends/strings/manifests.py,sha256=kmlanVUAZqIh0P95Mm8H20e8ib3gEgYHHUlkCXDQGFk,413
326
326
  ommlds/minichain/backends/strings/parsing.py,sha256=FbijHuHiIkOwC3jecUD-IXs7y12PS0ByCQeCfjJKuE8,1781
@@ -526,9 +526,9 @@ ommlds/wiki/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
526
526
  ommlds/wiki/utils/io.py,sha256=UKgDJGtmpnWvIqVd2mJc2QNPOqlToEY1GEveNp6_pMo,7088
527
527
  ommlds/wiki/utils/progress.py,sha256=EhvKcMFYtsarCQhIahlO6f0SboyAKP3UwUyrnVnP-Vk,3222
528
528
  ommlds/wiki/utils/xml.py,sha256=sNJNkZ9rT8B-kJMO6bRz8J1USy4fyPx0m2PwTX7vxYY,3846
529
- ommlds-0.0.0.dev513.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
530
- ommlds-0.0.0.dev513.dist-info/METADATA,sha256=hjYsfB2_iBou440IpGgVuJC6zvpRLoJ8UQ79M5VCBhE,3602
531
- ommlds-0.0.0.dev513.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
532
- ommlds-0.0.0.dev513.dist-info/entry_points.txt,sha256=Z5YWtX7ClfiCKdW-dd_CSVvM0h4yQpJPi-2G3q6gNFo,35
533
- ommlds-0.0.0.dev513.dist-info/top_level.txt,sha256=Rbnk5d5wi58vnAXx13WFZqdQ4VX8hBCS2hEL3WeXOhY,7
534
- ommlds-0.0.0.dev513.dist-info/RECORD,,
529
+ ommlds-0.0.0.dev515.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
530
+ ommlds-0.0.0.dev515.dist-info/METADATA,sha256=Ymblue2sqaQ1fupD_pdxYWr0xwhiL2JytUMrqYk_XFQ,3602
531
+ ommlds-0.0.0.dev515.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
532
+ ommlds-0.0.0.dev515.dist-info/entry_points.txt,sha256=Z5YWtX7ClfiCKdW-dd_CSVvM0h4yQpJPi-2G3q6gNFo,35
533
+ ommlds-0.0.0.dev515.dist-info/top_level.txt,sha256=Rbnk5d5wi58vnAXx13WFZqdQ4VX8hBCS2hEL3WeXOhY,7
534
+ ommlds-0.0.0.dev515.dist-info/RECORD,,