ommlds 0.0.0.dev480__py3-none-any.whl → 0.0.0.dev503__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.
Files changed (277) hide show
  1. ommlds/.omlish-manifests.json +100 -33
  2. ommlds/README.md +11 -0
  3. ommlds/__about__.py +9 -6
  4. ommlds/backends/anthropic/protocol/__init__.py +13 -1
  5. ommlds/backends/anthropic/protocol/_dataclasses.py +1625 -0
  6. ommlds/backends/anthropic/protocol/sse/events.py +2 -0
  7. ommlds/backends/cerebras/__init__.py +7 -0
  8. ommlds/backends/cerebras/_dataclasses.py +4254 -0
  9. ommlds/backends/cerebras/_marshal.py +24 -0
  10. ommlds/backends/cerebras/protocol.py +312 -0
  11. ommlds/backends/google/protocol/__init__.py +13 -0
  12. ommlds/backends/google/protocol/_dataclasses.py +5997 -0
  13. ommlds/backends/groq/__init__.py +7 -0
  14. ommlds/backends/groq/_dataclasses.py +3901 -0
  15. ommlds/backends/groq/clients.py +9 -0
  16. ommlds/backends/llamacpp/logging.py +4 -1
  17. ommlds/backends/mlx/caching.py +7 -3
  18. ommlds/backends/mlx/cli.py +10 -7
  19. ommlds/backends/mlx/generation.py +18 -16
  20. ommlds/backends/mlx/limits.py +10 -6
  21. ommlds/backends/mlx/loading.py +7 -4
  22. ommlds/backends/ollama/__init__.py +7 -0
  23. ommlds/backends/ollama/_dataclasses.py +3488 -0
  24. ommlds/backends/ollama/protocol.py +3 -0
  25. ommlds/backends/openai/protocol/__init__.py +15 -1
  26. ommlds/backends/openai/protocol/_dataclasses.py +7708 -0
  27. ommlds/backends/tavily/__init__.py +7 -0
  28. ommlds/backends/tavily/_dataclasses.py +1734 -0
  29. ommlds/backends/transformers/__init__.py +14 -0
  30. ommlds/cli/__init__.py +7 -0
  31. ommlds/cli/_dataclasses.py +3515 -0
  32. ommlds/cli/backends/catalog.py +0 -5
  33. ommlds/cli/backends/inject.py +70 -7
  34. ommlds/cli/backends/meta.py +82 -0
  35. ommlds/cli/content/messages.py +1 -1
  36. ommlds/cli/inject.py +11 -3
  37. ommlds/cli/main.py +137 -68
  38. ommlds/cli/rendering/types.py +6 -0
  39. ommlds/cli/secrets.py +2 -1
  40. ommlds/cli/sessions/base.py +1 -10
  41. ommlds/cli/sessions/chat/configs.py +9 -17
  42. ommlds/cli/sessions/chat/{chat → drivers}/ai/configs.py +3 -1
  43. ommlds/cli/sessions/chat/drivers/ai/events.py +57 -0
  44. ommlds/cli/sessions/chat/{chat → drivers}/ai/inject.py +10 -3
  45. ommlds/cli/sessions/chat/{chat → drivers}/ai/rendering.py +1 -1
  46. ommlds/cli/sessions/chat/{chat → drivers}/ai/services.py +1 -1
  47. ommlds/cli/sessions/chat/{chat → drivers}/ai/tools.py +4 -8
  48. ommlds/cli/sessions/chat/{chat → drivers}/ai/types.py +9 -0
  49. ommlds/cli/sessions/chat/drivers/configs.py +25 -0
  50. ommlds/cli/sessions/chat/drivers/events/inject.py +27 -0
  51. ommlds/cli/sessions/chat/drivers/events/injection.py +14 -0
  52. ommlds/cli/sessions/chat/drivers/events/manager.py +16 -0
  53. ommlds/cli/sessions/chat/drivers/events/types.py +38 -0
  54. ommlds/cli/sessions/chat/drivers/impl.py +50 -0
  55. ommlds/cli/sessions/chat/drivers/inject.py +70 -0
  56. ommlds/cli/sessions/chat/{chat → drivers}/state/configs.py +2 -0
  57. ommlds/cli/sessions/chat/drivers/state/ids.py +25 -0
  58. ommlds/cli/sessions/chat/drivers/state/inject.py +83 -0
  59. ommlds/cli/sessions/chat/{chat → drivers}/state/inmemory.py +0 -4
  60. ommlds/cli/sessions/chat/{chat → drivers}/state/storage.py +17 -10
  61. ommlds/cli/sessions/chat/{chat → drivers}/state/types.py +10 -5
  62. ommlds/cli/sessions/chat/{tools → drivers/tools}/configs.py +2 -2
  63. ommlds/cli/sessions/chat/drivers/tools/confirmation.py +44 -0
  64. ommlds/cli/sessions/chat/drivers/tools/errorhandling.py +39 -0
  65. ommlds/cli/sessions/chat/{tools → drivers/tools}/execution.py +3 -4
  66. ommlds/cli/sessions/chat/{tools → drivers/tools}/fs/inject.py +3 -3
  67. ommlds/cli/sessions/chat/{tools → drivers/tools}/inject.py +7 -12
  68. ommlds/cli/sessions/chat/{tools → drivers/tools}/injection.py +5 -5
  69. ommlds/cli/sessions/chat/{tools → drivers/tools}/rendering.py +3 -3
  70. ommlds/cli/sessions/chat/{tools → drivers/tools}/todo/inject.py +3 -3
  71. ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/tools.py +1 -1
  72. ommlds/cli/sessions/chat/drivers/types.py +31 -0
  73. ommlds/cli/sessions/chat/{chat → drivers}/user/configs.py +0 -3
  74. ommlds/cli/sessions/chat/drivers/user/inject.py +41 -0
  75. ommlds/cli/sessions/chat/facades/__init__.py +0 -0
  76. ommlds/cli/sessions/chat/facades/commands/__init__.py +0 -0
  77. ommlds/cli/sessions/chat/facades/commands/base.py +83 -0
  78. ommlds/cli/sessions/chat/facades/commands/configs.py +9 -0
  79. ommlds/cli/sessions/chat/facades/commands/inject.py +41 -0
  80. ommlds/cli/sessions/chat/facades/commands/injection.py +15 -0
  81. ommlds/cli/sessions/chat/facades/commands/manager.py +59 -0
  82. ommlds/cli/sessions/chat/facades/commands/simple.py +34 -0
  83. ommlds/cli/sessions/chat/facades/commands/types.py +13 -0
  84. ommlds/cli/sessions/chat/facades/configs.py +11 -0
  85. ommlds/cli/sessions/chat/facades/facade.py +26 -0
  86. ommlds/cli/sessions/chat/facades/inject.py +35 -0
  87. ommlds/cli/sessions/chat/facades/ui.py +34 -0
  88. ommlds/cli/sessions/chat/inject.py +8 -31
  89. ommlds/cli/sessions/chat/interfaces/__init__.py +0 -0
  90. ommlds/cli/sessions/chat/interfaces/bare/__init__.py +0 -0
  91. ommlds/cli/sessions/chat/interfaces/bare/configs.py +15 -0
  92. ommlds/cli/sessions/chat/interfaces/bare/inject.py +69 -0
  93. ommlds/cli/sessions/chat/interfaces/bare/interactive.py +49 -0
  94. ommlds/cli/sessions/chat/interfaces/bare/oneshot.py +21 -0
  95. ommlds/cli/sessions/chat/{tools/confirmation.py → interfaces/bare/tools.py} +3 -22
  96. ommlds/cli/sessions/chat/interfaces/base.py +13 -0
  97. ommlds/cli/sessions/chat/interfaces/configs.py +11 -0
  98. ommlds/cli/sessions/chat/interfaces/inject.py +29 -0
  99. ommlds/cli/sessions/chat/interfaces/textual/__init__.py +0 -0
  100. ommlds/cli/sessions/chat/interfaces/textual/app.py +310 -0
  101. ommlds/cli/sessions/chat/interfaces/textual/configs.py +11 -0
  102. ommlds/cli/sessions/chat/interfaces/textual/facades.py +19 -0
  103. ommlds/cli/sessions/chat/interfaces/textual/inject.py +97 -0
  104. ommlds/cli/sessions/chat/interfaces/textual/interface.py +24 -0
  105. ommlds/cli/sessions/chat/interfaces/textual/styles/__init__.py +29 -0
  106. ommlds/cli/sessions/chat/interfaces/textual/styles/input.tcss +53 -0
  107. ommlds/cli/sessions/chat/interfaces/textual/styles/markdown.tcss +7 -0
  108. ommlds/cli/sessions/chat/interfaces/textual/styles/messages.tcss +157 -0
  109. ommlds/cli/sessions/chat/interfaces/textual/tools.py +38 -0
  110. ommlds/cli/sessions/chat/interfaces/textual/widgets/__init__.py +0 -0
  111. ommlds/cli/sessions/chat/interfaces/textual/widgets/input.py +36 -0
  112. ommlds/cli/sessions/chat/interfaces/textual/widgets/messages.py +197 -0
  113. ommlds/cli/sessions/chat/session.py +8 -13
  114. ommlds/cli/sessions/completion/configs.py +3 -4
  115. ommlds/cli/sessions/completion/inject.py +1 -2
  116. ommlds/cli/sessions/completion/session.py +4 -8
  117. ommlds/cli/sessions/configs.py +10 -0
  118. ommlds/cli/sessions/embedding/configs.py +3 -4
  119. ommlds/cli/sessions/embedding/inject.py +1 -2
  120. ommlds/cli/sessions/embedding/session.py +4 -8
  121. ommlds/cli/sessions/inject.py +15 -15
  122. ommlds/cli/state/storage.py +7 -1
  123. ommlds/minichain/__init__.py +161 -38
  124. ommlds/minichain/_dataclasses.py +20452 -0
  125. ommlds/minichain/_typedvalues.py +11 -4
  126. ommlds/minichain/backends/impls/anthropic/names.py +3 -3
  127. ommlds/minichain/backends/impls/anthropic/protocol.py +2 -2
  128. ommlds/minichain/backends/impls/anthropic/stream.py +1 -1
  129. ommlds/minichain/backends/impls/cerebras/__init__.py +0 -0
  130. ommlds/minichain/backends/impls/cerebras/chat.py +80 -0
  131. ommlds/minichain/backends/impls/cerebras/names.py +45 -0
  132. ommlds/minichain/backends/impls/cerebras/protocol.py +143 -0
  133. ommlds/minichain/backends/impls/cerebras/stream.py +125 -0
  134. ommlds/minichain/backends/impls/duckduckgo/search.py +5 -1
  135. ommlds/minichain/backends/impls/google/names.py +6 -0
  136. ommlds/minichain/backends/impls/google/stream.py +1 -1
  137. ommlds/minichain/backends/impls/google/tools.py +2 -2
  138. ommlds/minichain/backends/impls/groq/chat.py +2 -0
  139. ommlds/minichain/backends/impls/groq/protocol.py +2 -2
  140. ommlds/minichain/backends/impls/groq/stream.py +3 -1
  141. ommlds/minichain/backends/impls/huggingface/repos.py +1 -5
  142. ommlds/minichain/backends/impls/llamacpp/chat.py +6 -3
  143. ommlds/minichain/backends/impls/llamacpp/completion.py +7 -3
  144. ommlds/minichain/backends/impls/llamacpp/stream.py +6 -3
  145. ommlds/minichain/backends/impls/mlx/chat.py +6 -3
  146. ommlds/minichain/backends/impls/ollama/chat.py +51 -57
  147. ommlds/minichain/backends/impls/ollama/protocol.py +144 -0
  148. ommlds/minichain/backends/impls/openai/format.py +4 -3
  149. ommlds/minichain/backends/impls/openai/names.py +3 -1
  150. ommlds/minichain/backends/impls/openai/stream.py +33 -1
  151. ommlds/minichain/backends/impls/sentencepiece/tokens.py +9 -6
  152. ommlds/minichain/backends/impls/tinygrad/chat.py +7 -4
  153. ommlds/minichain/backends/impls/tokenizers/tokens.py +9 -6
  154. ommlds/minichain/backends/impls/transformers/sentence.py +5 -2
  155. ommlds/minichain/backends/impls/transformers/tokens.py +9 -6
  156. ommlds/minichain/backends/impls/transformers/transformers.py +10 -8
  157. ommlds/minichain/backends/strings/resolving.py +1 -1
  158. ommlds/minichain/chat/content.py +42 -0
  159. ommlds/minichain/chat/messages.py +43 -39
  160. ommlds/minichain/chat/stream/joining.py +36 -12
  161. ommlds/minichain/chat/stream/types.py +1 -1
  162. ommlds/minichain/chat/templating.py +3 -3
  163. ommlds/minichain/content/__init__.py +19 -3
  164. ommlds/minichain/content/_marshal.py +181 -55
  165. ommlds/minichain/content/code.py +26 -0
  166. ommlds/minichain/content/composite.py +28 -0
  167. ommlds/minichain/content/content.py +27 -0
  168. ommlds/minichain/content/dynamic.py +12 -0
  169. ommlds/minichain/content/emphasis.py +27 -0
  170. ommlds/minichain/content/images.py +2 -2
  171. ommlds/minichain/content/json.py +2 -2
  172. ommlds/minichain/content/link.py +13 -0
  173. ommlds/minichain/content/markdown.py +12 -0
  174. ommlds/minichain/content/metadata.py +10 -0
  175. ommlds/minichain/content/namespaces.py +8 -0
  176. ommlds/minichain/content/placeholders.py +10 -9
  177. ommlds/minichain/content/quote.py +26 -0
  178. ommlds/minichain/content/raw.py +49 -0
  179. ommlds/minichain/content/recursive.py +12 -0
  180. ommlds/minichain/content/section.py +26 -0
  181. ommlds/minichain/content/sequence.py +17 -3
  182. ommlds/minichain/content/standard.py +32 -0
  183. ommlds/minichain/content/tag.py +28 -0
  184. ommlds/minichain/content/templates.py +13 -0
  185. ommlds/minichain/content/text.py +2 -2
  186. ommlds/minichain/content/transform/__init__.py +0 -0
  187. ommlds/minichain/content/transform/json.py +55 -0
  188. ommlds/minichain/content/transform/markdown.py +8 -0
  189. ommlds/minichain/content/transform/materialize.py +51 -0
  190. ommlds/minichain/content/transform/metadata.py +16 -0
  191. ommlds/minichain/content/{prepare.py → transform/prepare.py} +10 -15
  192. ommlds/minichain/content/transform/recursive.py +97 -0
  193. ommlds/minichain/content/transform/standard.py +43 -0
  194. ommlds/minichain/content/{transforms → transform}/stringify.py +1 -7
  195. ommlds/minichain/content/transform/strings.py +33 -0
  196. ommlds/minichain/content/transform/templates.py +25 -0
  197. ommlds/minichain/content/visitors.py +231 -0
  198. ommlds/minichain/lib/fs/tools/read.py +1 -1
  199. ommlds/minichain/lib/fs/tools/recursivels/rendering.py +1 -1
  200. ommlds/minichain/lib/fs/tools/recursivels/running.py +1 -1
  201. ommlds/minichain/lib/todo/tools/write.py +2 -1
  202. ommlds/minichain/lib/todo/types.py +1 -1
  203. ommlds/minichain/metadata.py +56 -2
  204. ommlds/minichain/resources.py +22 -1
  205. ommlds/minichain/services/README.md +154 -0
  206. ommlds/minichain/services/__init__.py +6 -2
  207. ommlds/minichain/services/_marshal.py +46 -10
  208. ommlds/minichain/services/_origclasses.py +11 -0
  209. ommlds/minichain/services/_typedvalues.py +8 -3
  210. ommlds/minichain/services/requests.py +73 -3
  211. ommlds/minichain/services/responses.py +73 -3
  212. ommlds/minichain/services/services.py +9 -0
  213. ommlds/minichain/stream/services.py +24 -1
  214. ommlds/minichain/text/applypatch.py +2 -1
  215. ommlds/minichain/text/toolparsing/llamacpp/types.py +1 -1
  216. ommlds/minichain/tokens/specials.py +1 -1
  217. ommlds/minichain/tools/execution/catalog.py +1 -1
  218. ommlds/minichain/tools/execution/errorhandling.py +36 -0
  219. ommlds/minichain/tools/execution/errors.py +2 -2
  220. ommlds/minichain/tools/execution/executors.py +1 -1
  221. ommlds/minichain/tools/fns.py +1 -1
  222. ommlds/minichain/tools/jsonschema.py +2 -2
  223. ommlds/minichain/tools/reflect.py +6 -6
  224. ommlds/minichain/tools/types.py +12 -15
  225. ommlds/minichain/vectors/_marshal.py +1 -1
  226. ommlds/minichain/vectors/embeddings.py +1 -1
  227. ommlds/minichain/wrappers/__init__.py +7 -0
  228. ommlds/minichain/wrappers/firstinwins.py +144 -0
  229. ommlds/minichain/wrappers/instrument.py +146 -0
  230. ommlds/minichain/wrappers/retry.py +168 -0
  231. ommlds/minichain/wrappers/services.py +98 -0
  232. ommlds/minichain/wrappers/stream.py +57 -0
  233. ommlds/nanochat/rustbpe/README.md +9 -0
  234. ommlds/nanochat/tokenizers.py +40 -6
  235. ommlds/specs/mcp/clients.py +146 -0
  236. ommlds/specs/mcp/protocol.py +123 -18
  237. ommlds/tools/git.py +82 -65
  238. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/METADATA +13 -11
  239. ommlds-0.0.0.dev503.dist-info/RECORD +520 -0
  240. ommlds/cli/sessions/chat/chat/state/inject.py +0 -36
  241. ommlds/cli/sessions/chat/chat/user/inject.py +0 -62
  242. ommlds/cli/sessions/chat/chat/user/interactive.py +0 -31
  243. ommlds/cli/sessions/chat/chat/user/oneshot.py +0 -25
  244. ommlds/cli/sessions/chat/chat/user/types.py +0 -15
  245. ommlds/cli/sessions/chat/driver.py +0 -43
  246. ommlds/minichain/content/materialize.py +0 -196
  247. ommlds/minichain/content/simple.py +0 -47
  248. ommlds/minichain/content/transforms/base.py +0 -46
  249. ommlds/minichain/content/transforms/interleave.py +0 -70
  250. ommlds/minichain/content/transforms/squeeze.py +0 -72
  251. ommlds/minichain/content/transforms/strings.py +0 -24
  252. ommlds/minichain/content/types.py +0 -43
  253. ommlds/minichain/stream/wrap.py +0 -62
  254. ommlds-0.0.0.dev480.dist-info/RECORD +0 -427
  255. /ommlds/cli/sessions/chat/{chat → drivers}/__init__.py +0 -0
  256. /ommlds/cli/sessions/chat/{chat → drivers}/ai/__init__.py +0 -0
  257. /ommlds/cli/sessions/chat/{chat → drivers}/ai/injection.py +0 -0
  258. /ommlds/cli/sessions/chat/{chat/state → drivers/events}/__init__.py +0 -0
  259. /ommlds/cli/sessions/chat/{chat/user → drivers/phases}/__init__.py +0 -0
  260. /ommlds/cli/sessions/chat/{phases → drivers/phases}/inject.py +0 -0
  261. /ommlds/cli/sessions/chat/{phases → drivers/phases}/injection.py +0 -0
  262. /ommlds/cli/sessions/chat/{phases → drivers/phases}/manager.py +0 -0
  263. /ommlds/cli/sessions/chat/{phases → drivers/phases}/types.py +0 -0
  264. /ommlds/cli/sessions/chat/{phases → drivers/state}/__init__.py +0 -0
  265. /ommlds/cli/sessions/chat/{tools → drivers/tools}/__init__.py +0 -0
  266. /ommlds/cli/sessions/chat/{tools → drivers/tools}/fs/__init__.py +0 -0
  267. /ommlds/cli/sessions/chat/{tools → drivers/tools}/fs/configs.py +0 -0
  268. /ommlds/cli/sessions/chat/{tools → drivers/tools}/todo/__init__.py +0 -0
  269. /ommlds/cli/sessions/chat/{tools → drivers/tools}/todo/configs.py +0 -0
  270. /ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/__init__.py +0 -0
  271. /ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/configs.py +0 -0
  272. /ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/inject.py +0 -0
  273. /ommlds/{minichain/content/transforms → cli/sessions/chat/drivers/user}/__init__.py +0 -0
  274. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/WHEEL +0 -0
  275. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/entry_points.txt +0 -0
  276. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/licenses/LICENSE +0 -0
  277. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,38 @@
1
+ from omlish.formats import json
2
+
3
+ from ...... import minichain as mc
4
+ from ...drivers.tools.confirmation import ToolExecutionConfirmation
5
+ from ...drivers.tools.confirmation import ToolExecutionRequestDeniedError
6
+ from .app import ChatAppGetter
7
+
8
+
9
+ ##
10
+
11
+
12
+ class ChatAppToolExecutionConfirmation(ToolExecutionConfirmation):
13
+ def __init__(
14
+ self,
15
+ *,
16
+ app: ChatAppGetter,
17
+ ) -> None:
18
+ super().__init__()
19
+
20
+ self._app = app
21
+
22
+ async def confirm_tool_execution_or_raise(
23
+ self,
24
+ use: 'mc.ToolUse',
25
+ entry: 'mc.ToolCatalogEntry',
26
+ ) -> None:
27
+ tr_dct = dict(
28
+ id=use.id,
29
+ name=entry.spec.name,
30
+ args=use.args,
31
+ # spec=msh.marshal(tce.spec),
32
+ )
33
+
34
+ if not await (await self._app()).confirm_tool_use(
35
+ 'Execute requested tool?',
36
+ json.dumps_pretty(tr_dct),
37
+ ):
38
+ raise ToolExecutionRequestDeniedError
@@ -0,0 +1,36 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+ from omdev.tui import textual as tx
5
+
6
+
7
+ ##
8
+
9
+
10
+ class InputTextArea(tx.TextArea):
11
+ @dc.dataclass()
12
+ class Submitted(tx.Message):
13
+ text: str
14
+
15
+ def __init__(self, **kwargs: ta.Any) -> None:
16
+ super().__init__(**kwargs)
17
+
18
+ async def _on_key(self, event: tx.Key) -> None:
19
+ if event.key == 'enter':
20
+ event.prevent_default()
21
+ event.stop()
22
+
23
+ if text := self.text.strip():
24
+ self.post_message(self.Submitted(text))
25
+
26
+ else:
27
+ await super()._on_key(event)
28
+
29
+
30
+ class InputOuter(tx.Static):
31
+ def compose(self) -> tx.ComposeResult:
32
+ with tx.Vertical(id='input-vertical'):
33
+ with tx.Vertical(id='input-vertical2'):
34
+ with tx.Horizontal(id='input-horizontal'):
35
+ yield tx.Static('>', id='input-glyph')
36
+ yield InputTextArea(placeholder='...', id='input')
@@ -0,0 +1,197 @@
1
+ import abc
2
+ import asyncio
3
+ import typing as ta
4
+
5
+ from omdev.tui import textual as tx
6
+ from omlish import lang
7
+
8
+
9
+ ##
10
+
11
+
12
+ class MessagesContainer(tx.VerticalScroll):
13
+ pass
14
+
15
+
16
+ ##
17
+
18
+
19
+ class Message(tx.Static, lang.Abstract):
20
+ def __init__(self, *args: ta.Any, **kwargs: ta.Any) -> None:
21
+ super().__init__(*args, **kwargs)
22
+
23
+ self.add_class('message')
24
+
25
+
26
+ #
27
+
28
+
29
+ class WelcomeMessage(Message):
30
+ def __init__(self, content: str) -> None:
31
+ super().__init__()
32
+
33
+ self.add_class('welcome-message')
34
+
35
+ self._content = content
36
+
37
+ def compose(self) -> tx.ComposeResult:
38
+ with tx.Vertical(classes='welcome-message-outer message-outer'):
39
+ yield tx.Static(self._content, classes='welcome-message-content')
40
+
41
+
42
+ #
43
+
44
+
45
+ class UserMessage(Message):
46
+ def __init__(self, content: str) -> None:
47
+ super().__init__()
48
+
49
+ self.add_class('user-message')
50
+
51
+ self._content = content
52
+
53
+ def compose(self) -> tx.ComposeResult:
54
+ with tx.Horizontal(classes='user-message-outer message-outer'):
55
+ yield tx.Static('> ', classes='user-message-glyph message-glyph')
56
+ with tx.Vertical(classes='user-message-inner message-inner'):
57
+ yield tx.Static(self._content)
58
+
59
+
60
+ #
61
+
62
+
63
+ class AiMessage(Message, lang.Abstract):
64
+ def __init__(self) -> None:
65
+ super().__init__()
66
+
67
+ self.add_class('ai-message')
68
+
69
+ def compose(self) -> tx.ComposeResult:
70
+ with tx.Horizontal(classes='ai-message-outer message-outer'):
71
+ yield tx.Static('< ', classes='ai-message-glyph message-glyph')
72
+ with tx.Vertical(classes='ai-message-inner message-inner'):
73
+ yield from self._compose_content()
74
+
75
+ @abc.abstractmethod
76
+ def _compose_content(self) -> ta.Generator:
77
+ raise NotImplementedError
78
+
79
+
80
+ class StaticAiMessage(AiMessage):
81
+ def __init__(
82
+ self,
83
+ content: str,
84
+ *,
85
+ markdown: bool = False,
86
+ ) -> None:
87
+ super().__init__()
88
+
89
+ self._content = content
90
+ self._markdown = markdown
91
+
92
+ def _compose_content(self) -> ta.Generator:
93
+ if self._markdown:
94
+ yield tx.Markdown(self._content)
95
+ else:
96
+ yield tx.Static(self._content)
97
+
98
+
99
+ class StreamAiMessage(AiMessage):
100
+ def __init__(self, content: str) -> None:
101
+ super().__init__()
102
+
103
+ self._content = content
104
+
105
+ def _compose_content(self) -> ta.Generator:
106
+ yield tx.Markdown('')
107
+
108
+ _stream_: tx.MarkdownStream | None = None
109
+
110
+ def _stream(self) -> tx.MarkdownStream:
111
+ if self._stream_ is None:
112
+ self._stream_ = tx.Markdown.get_stream(self.query_one(tx.Markdown))
113
+ return self._stream_
114
+
115
+ async def write_initial_content(self) -> None:
116
+ if self._content:
117
+ await self._stream().write(self._content)
118
+
119
+ async def append_content(self, content: str) -> None:
120
+ if not content:
121
+ return
122
+
123
+ self._content += content
124
+ await self._stream().write(content)
125
+
126
+ async def stop_stream(self) -> None:
127
+ if (stream := self._stream_) is None:
128
+ return
129
+
130
+ await stream.stop()
131
+ self._stream_ = None
132
+
133
+
134
+ #
135
+
136
+
137
+ class ToolConfirmationControls(tx.Static):
138
+ class Allowed(tx.Message):
139
+ pass
140
+
141
+ def compose(self) -> tx.ComposeResult:
142
+ yield tx.Button('Allow', action='allow')
143
+
144
+ def action_allow(self) -> None:
145
+ self.post_message(self.Allowed())
146
+
147
+
148
+ class ToolConfirmationMessage(Message):
149
+ def __init__(
150
+ self,
151
+ outer_content: str,
152
+ inner_content: str,
153
+ fut: asyncio.Future[bool],
154
+ ) -> None:
155
+ super().__init__()
156
+
157
+ self.add_class('tool-confirmation-message')
158
+
159
+ self._outer_content = outer_content
160
+ self._inner_content = inner_content
161
+ self._fut = fut
162
+
163
+ def compose(self) -> tx.ComposeResult:
164
+ with tx.Horizontal(classes='tool-confirmation-message-outer message-outer'):
165
+ yield tx.Static('? ', classes='tool-confirmation-message-glyph message-glyph')
166
+ with tx.Vertical(classes='tool-confirmation-message-inner tool-confirmation-message-inner-open message-inner'): # noqa
167
+ yield tx.Static(self._outer_content, classes='tool-confirmation-message-outer-content')
168
+ yield tx.Static(self._inner_content, classes='tool-confirmation-message-inner-content')
169
+ yield ToolConfirmationControls(classes='tool-confirmation-message-controls')
170
+
171
+ @tx.on(ToolConfirmationControls.Allowed)
172
+ async def on_allowed(self, event: ToolConfirmationControls.Allowed) -> None:
173
+ inner = self.query_one(tx.Vertical)
174
+ await inner.query_one(ToolConfirmationControls).remove()
175
+ inner.remove_class('tool-confirmation-message-inner-open')
176
+ inner.add_class('tool-confirmation-message-inner-closed')
177
+ inner.query_one('.tool-confirmation-message-outer-content', tx.Static).update('Tool use confirmed.')
178
+
179
+ self._fut.set_result(True)
180
+
181
+
182
+ #
183
+
184
+
185
+ class UiMessage(Message):
186
+ def __init__(self, content: str) -> None:
187
+ super().__init__()
188
+
189
+ self.add_class('ui-message')
190
+
191
+ self._content = content
192
+
193
+ def compose(self) -> tx.ComposeResult:
194
+ with tx.Horizontal(classes='ui-message-outer message-outer'):
195
+ yield tx.Static('~ ', classes='ui-message-glyph message-glyph')
196
+ with tx.Vertical(classes='ui-message-inner message-inner'):
197
+ yield tx.Static(self._content)
@@ -1,27 +1,22 @@
1
- from omlish import dataclasses as dc
1
+ import typing as ta
2
2
 
3
3
  from ..base import Session
4
- from .configs import ChatConfig
5
- from .driver import ChatDriver
4
+ from .interfaces.base import ChatInterface
6
5
 
7
6
 
8
7
  ##
9
8
 
10
9
 
11
- class ChatSession(Session['ChatSession.Config']):
12
- @dc.dataclass(frozen=True)
13
- class Config(Session.Config, ChatConfig):
14
- pass
15
-
10
+ @ta.final
11
+ class ChatSession(Session):
16
12
  def __init__(
17
13
  self,
18
- config: Config,
19
14
  *,
20
- driver: ChatDriver,
15
+ interface: ChatInterface,
21
16
  ) -> None:
22
- super().__init__(config)
17
+ super().__init__()
23
18
 
24
- self._driver = driver
19
+ self._interface = interface
25
20
 
26
21
  async def run(self) -> None:
27
- await self._driver.run()
22
+ await self._interface.run()
@@ -1,6 +1,7 @@
1
1
  from omlish import dataclasses as dc
2
2
 
3
3
  from .... import minichain as mc
4
+ from ..configs import SessionConfig
4
5
 
5
6
 
6
7
  ##
@@ -12,10 +13,8 @@ DEFAULT_BACKEND = 'openai'
12
13
  ##
13
14
 
14
15
 
15
- @dc.dataclass(frozen=True)
16
- class CompletionConfig:
16
+ @dc.dataclass(frozen=True, kw_only=True)
17
+ class CompletionConfig(SessionConfig):
17
18
  content: 'mc.Content'
18
19
 
19
- _: dc.KW_ONLY
20
-
21
20
  backend: str | None = None
@@ -1,4 +1,3 @@
1
- from omlish import dataclasses as dc
2
1
  from omlish import inject as inj
3
2
  from omlish import lang
4
3
 
@@ -23,7 +22,7 @@ def bind_completion(cfg: CompletionConfig) -> inj.Elements:
23
22
  #
24
23
 
25
24
  els.extend([
26
- inj.bind(_session.CompletionSession.Config(**dc.asdict(cfg))),
25
+ inj.bind(cfg),
27
26
  inj.bind(Session, to_ctor=_session.CompletionSession, singleton=True),
28
27
  ])
29
28
 
@@ -1,5 +1,4 @@
1
1
  from omlish import check
2
- from omlish import dataclasses as dc
3
2
 
4
3
  from .... import minichain as mc
5
4
  from ...backends.types import CompletionServiceBackendProvider
@@ -10,19 +9,16 @@ from .configs import CompletionConfig
10
9
  ##
11
10
 
12
11
 
13
- class CompletionSession(Session['CompletionSession.Config']):
14
- @dc.dataclass(frozen=True)
15
- class Config(Session.Config, CompletionConfig):
16
- pass
17
-
12
+ class CompletionSession(Session):
18
13
  def __init__(
19
14
  self,
20
- config: Config,
15
+ config: CompletionConfig,
21
16
  *,
22
17
  service_provider: CompletionServiceBackendProvider,
23
18
  ) -> None:
24
- super().__init__(config)
19
+ super().__init__()
25
20
 
21
+ self._config = config
26
22
  self._service_provider = service_provider
27
23
 
28
24
  async def run(self) -> None:
@@ -0,0 +1,10 @@
1
+ from omlish import dataclasses as dc
2
+ from omlish import lang
3
+
4
+
5
+ ##
6
+
7
+
8
+ @dc.dataclass(frozen=True, kw_only=True)
9
+ class SessionConfig(lang.Abstract):
10
+ pass
@@ -1,6 +1,7 @@
1
1
  from omlish import dataclasses as dc
2
2
 
3
3
  from .... import minichain as mc
4
+ from ..configs import SessionConfig
4
5
 
5
6
 
6
7
  ##
@@ -12,10 +13,8 @@ DEFAULT_BACKEND = 'openai'
12
13
  ##
13
14
 
14
15
 
15
- @dc.dataclass(frozen=True)
16
- class EmbeddingConfig:
16
+ @dc.dataclass(frozen=True, kw_only=True)
17
+ class EmbeddingConfig(SessionConfig):
17
18
  content: 'mc.Content'
18
19
 
19
- _: dc.KW_ONLY
20
-
21
20
  backend: str | None = None
@@ -1,4 +1,3 @@
1
- from omlish import dataclasses as dc
2
1
  from omlish import inject as inj
3
2
  from omlish import lang
4
3
 
@@ -23,7 +22,7 @@ def bind_embedding(cfg: EmbeddingConfig) -> inj.Elements:
23
22
  #
24
23
 
25
24
  els.extend([
26
- inj.bind(_session.EmbeddingSession.Config(**dc.asdict(cfg))),
25
+ inj.bind(cfg),
27
26
  inj.bind(Session, to_ctor=_session.EmbeddingSession, singleton=True),
28
27
  ])
29
28
 
@@ -1,4 +1,3 @@
1
- from omlish import dataclasses as dc
2
1
  from omlish.formats import json
3
2
 
4
3
  from .... import minichain as mc
@@ -10,19 +9,16 @@ from .configs import EmbeddingConfig
10
9
  ##
11
10
 
12
11
 
13
- class EmbeddingSession(Session['EmbeddingSession.Config']):
14
- @dc.dataclass(frozen=True)
15
- class Config(Session.Config, EmbeddingConfig):
16
- pass
17
-
12
+ class EmbeddingSession(Session):
18
13
  def __init__(
19
14
  self,
20
- config: Config,
15
+ config: EmbeddingConfig,
21
16
  *,
22
17
  service_provider: EmbeddingServiceBackendProvider,
23
18
  ) -> None:
24
- super().__init__(config)
19
+ super().__init__()
25
20
 
21
+ self._config = config
26
22
  self._service_provider = service_provider
27
23
 
28
24
  async def run(self) -> None:
@@ -1,34 +1,34 @@
1
- import typing as ta
2
-
3
1
  from omlish import inject as inj
4
2
  from omlish import lang
5
3
 
4
+ from .chat.configs import ChatConfig
5
+ from .completion.configs import CompletionConfig
6
+ from .configs import SessionConfig
7
+ from .embedding.configs import EmbeddingConfig
8
+
6
9
 
7
10
  with lang.auto_proxy_import(globals()):
8
- from .chat import configs as _chat_cfgs
9
- from .chat import inject as _chat_inj
10
- from .completion import configs as _completion_cfgs
11
- from .completion import inject as _completion_inj
12
- from .embedding import configs as _embedding_cfgs
13
- from .embedding import inject as _embedding_inj
11
+ from .chat import inject as _chat
12
+ from .completion import inject as _completion
13
+ from .embedding import inject as _embedding
14
14
 
15
15
 
16
16
  ##
17
17
 
18
18
 
19
- def bind_sessions(cfg: ta.Any) -> inj.Elements:
19
+ def bind_sessions(cfg: SessionConfig) -> inj.Elements:
20
20
  els: list[inj.Elemental] = []
21
21
 
22
22
  #
23
23
 
24
- if isinstance(cfg, _chat_cfgs.ChatConfig):
25
- els.append(_chat_inj.bind_chat(cfg))
24
+ if isinstance(cfg, ChatConfig):
25
+ els.append(_chat.bind_chat(cfg))
26
26
 
27
- elif isinstance(cfg, _completion_cfgs.CompletionConfig):
28
- els.append(_completion_inj.bind_completion(cfg))
27
+ elif isinstance(cfg, CompletionConfig):
28
+ els.append(_completion.bind_completion(cfg))
29
29
 
30
- elif isinstance(cfg, _embedding_cfgs.EmbeddingConfig):
31
- els.append(_embedding_inj.bind_embedding(cfg))
30
+ elif isinstance(cfg, EmbeddingConfig):
31
+ els.append(_embedding.bind_embedding(cfg))
32
32
 
33
33
  else:
34
34
  raise TypeError(cfg)
@@ -1,4 +1,5 @@
1
1
  import abc
2
+ import datetime
2
3
  import os.path
3
4
  import typing as ta
4
5
 
@@ -52,8 +53,12 @@ STATE_VERSION = 0
52
53
  @dc.dataclass(frozen=True)
53
54
  class MarshaledState:
54
55
  version: int
56
+
55
57
  payload: ta.Any
56
58
 
59
+ created_at: datetime.datetime | None = dc.field(default_factory=lang.utcnow)
60
+ updated_at: datetime.datetime | None = dc.field(default_factory=lang.utcnow)
61
+
57
62
 
58
63
  class MarshalStateStorage(StateStorage, lang.Abstract):
59
64
  def __init__(
@@ -75,6 +80,7 @@ class MarshalStateStorage(StateStorage, lang.Abstract):
75
80
  ms = MarshaledState(
76
81
  version=self._version,
77
82
  payload=msh.marshal(obj, ty),
83
+ updated_at=lang.utcnow(),
78
84
  )
79
85
  return msh.marshal(ms)
80
86
 
@@ -102,7 +108,7 @@ class JsonFileStateStorage(MarshalStateStorage):
102
108
  return json.loads(data)
103
109
 
104
110
  def _save_file_data(self, data: ta.Any) -> None:
105
- data = json.dumps_pretty(data)
111
+ data = json.dumps_compact(data)
106
112
  with open(self._file, 'w') as f:
107
113
  f.write(data)
108
114