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
@@ -1,9 +1,11 @@
1
1
  import abc
2
2
  import datetime
3
3
  import typing as ta
4
+ import uuid
4
5
 
5
6
  from omlish import dataclasses as dc
6
7
  from omlish import lang
8
+ from omlish import typedvalues as tv
7
9
 
8
10
  from ...... import minichain as mc
9
11
 
@@ -11,6 +13,13 @@ from ...... import minichain as mc
11
13
  ##
12
14
 
13
15
 
16
+ class ChatId(tv.UniqueScalarTypedValue[uuid.UUID]):
17
+ pass
18
+
19
+
20
+ ##
21
+
22
+
14
23
  @dc.dataclass(frozen=True)
15
24
  class ChatState:
16
25
  name: str | None = None
@@ -18,7 +27,7 @@ class ChatState:
18
27
  created_at: datetime.datetime = dc.field(default_factory=lang.utcnow)
19
28
  updated_at: datetime.datetime = dc.field(default_factory=lang.utcnow)
20
29
 
21
- chat: mc.Chat = ()
30
+ chat: 'mc.Chat' = ()
22
31
 
23
32
 
24
33
  ##
@@ -29,10 +38,6 @@ class ChatStateManager(lang.Abstract):
29
38
  def get_state(self) -> ta.Awaitable[ChatState]:
30
39
  raise NotImplementedError
31
40
 
32
- @abc.abstractmethod
33
- def clear_state(self) -> ta.Awaitable[ChatState]:
34
- raise NotImplementedError
35
-
36
41
  @abc.abstractmethod
37
42
  def extend_chat(self, chat_additions: 'mc.Chat') -> ta.Awaitable[ChatState]:
38
43
  raise NotImplementedError
@@ -9,10 +9,10 @@ from omlish import lang
9
9
 
10
10
  @dc.dataclass(frozen=True, kw_only=True)
11
11
  class ToolsConfig:
12
- silent: bool = False
13
- dangerous_no_confirmation: bool = False
14
12
  enabled_tools: ta.Iterable[str] | None = None
15
13
 
14
+ verbose: bool = False
15
+
16
16
 
17
17
  ##
18
18
 
@@ -0,0 +1,44 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+ from omlish import lang
5
+
6
+ from ...... import minichain as mc
7
+
8
+
9
+ ##
10
+
11
+
12
+ class ToolExecutionRequestDeniedError(Exception):
13
+ pass
14
+
15
+
16
+ class ToolExecutionConfirmation(lang.Abstract):
17
+ @abc.abstractmethod
18
+ def confirm_tool_execution_or_raise(
19
+ self,
20
+ use: 'mc.ToolUse',
21
+ entry: 'mc.ToolCatalogEntry',
22
+ ) -> ta.Awaitable[None]:
23
+ raise NotImplementedError
24
+
25
+
26
+ ##
27
+
28
+
29
+ class AlwaysDenyToolExecutionConfirmation(ToolExecutionConfirmation):
30
+ async def confirm_tool_execution_or_raise(
31
+ self,
32
+ use: 'mc.ToolUse',
33
+ entry: 'mc.ToolCatalogEntry',
34
+ ) -> None:
35
+ raise ToolExecutionRequestDeniedError
36
+
37
+
38
+ class UnsafeAlwaysAllowToolExecutionConfirmation(ToolExecutionConfirmation):
39
+ async def confirm_tool_execution_or_raise(
40
+ self,
41
+ use: 'mc.ToolUse',
42
+ entry: 'mc.ToolCatalogEntry',
43
+ ) -> None:
44
+ pass
@@ -0,0 +1,39 @@
1
+ import typing as ta
2
+
3
+ from omlish import check
4
+
5
+ from ...... import minichain as mc
6
+ from .execution import ToolUseExecutor
7
+
8
+
9
+ ##
10
+
11
+
12
+ class ErrorHandlingToolUseExecutor(ToolUseExecutor):
13
+ def __init__(
14
+ self,
15
+ *,
16
+ wrapped: ToolUseExecutor,
17
+ ) -> None:
18
+ super().__init__()
19
+
20
+ self._wrapped = wrapped
21
+
22
+ async def execute_tool_use(
23
+ self,
24
+ use: 'mc.ToolUse',
25
+ *ctx_items: ta.Any,
26
+ ) -> 'mc.ToolUseResultMessage':
27
+ try:
28
+ return await self._wrapped.execute_tool_use(use, *ctx_items)
29
+
30
+ except mc.ToolExecutionError as txe: # noqa
31
+ s = check.non_empty_str(check.isinstance(txe.content, str))
32
+
33
+ return mc.ToolUseResultMessage(
34
+ mc.ToolUseResult(
35
+ id=use.id,
36
+ name=use.name,
37
+ c=s,
38
+ ),
39
+ )
@@ -4,7 +4,7 @@ import typing as ta
4
4
  from omlish import check
5
5
  from omlish import lang
6
6
 
7
- from ..... import minichain as mc
7
+ from ...... import minichain as mc
8
8
  from .confirmation import ToolExecutionConfirmation
9
9
 
10
10
 
@@ -37,7 +37,7 @@ class ToolUseExecutorImpl(ToolUseExecutor):
37
37
  *,
38
38
  catalog: 'mc.ToolCatalog',
39
39
  ctx_provider: ToolContextProvider,
40
- confirmation: ToolExecutionConfirmation | None = None,
40
+ confirmation: ToolExecutionConfirmation,
41
41
  ) -> None:
42
42
  super().__init__()
43
43
 
@@ -52,8 +52,7 @@ class ToolUseExecutorImpl(ToolUseExecutor):
52
52
  ) -> 'mc.ToolUseResultMessage':
53
53
  tce = self._catalog.by_name[check.non_empty_str(use.name)]
54
54
 
55
- if self._confirmation is not None:
56
- await self._confirmation.confirm_tool_execution_or_raise(use, tce)
55
+ await self._confirmation.confirm_tool_execution_or_raise(use, tce)
57
56
 
58
57
  return await mc.execute_tool_use(
59
58
  mc.ToolContext(
@@ -12,9 +12,9 @@ from .configs import FsToolSetConfig
12
12
 
13
13
 
14
14
  def bind_fs_tools(cfg: FsToolSetConfig) -> inj.Elements:
15
- from ......minichain.lib.fs.context import FsContext
16
- from ......minichain.lib.fs.tools.ls import ls_tool
17
- from ......minichain.lib.fs.tools.read import read_tool
15
+ from .......minichain.lib.fs.context import FsContext
16
+ from .......minichain.lib.fs.tools.ls import ls_tool
17
+ from .......minichain.lib.fs.tools.read import read_tool
18
18
 
19
19
  return inj.as_elements(
20
20
  tool_catalog_entries().bind_item_consts(
@@ -2,15 +2,15 @@ from omlish import check
2
2
  from omlish import inject as inj
3
3
  from omlish import lang
4
4
 
5
- from ..... import minichain as mc
6
- from .configs import ToolsConfig
5
+ from ...... import minichain as mc
6
+ from ..configs import ToolsConfig
7
7
  from .injection import ToolSetBinder
8
8
  from .injection import tool_catalog_entries
9
9
  from .injection import tool_context_providers
10
10
 
11
11
 
12
12
  with lang.auto_proxy_import(globals()):
13
- from . import confirmation as _confirmation
13
+ from . import errorhandling as _errorhandling
14
14
  from . import execution as _execution
15
15
  from . import rendering as _rendering
16
16
 
@@ -58,11 +58,11 @@ def bind_tools(cfg: ToolsConfig = ToolsConfig()) -> inj.Elements:
58
58
 
59
59
  els.append(exec_stack.push_bind(to_ctor=_execution.ToolUseExecutorImpl, singleton=True))
60
60
 
61
- if not cfg.silent:
62
- els.append(exec_stack.push_bind(to_ctor=_rendering.ResultRenderingToolUseExecutor, singleton=True))
61
+ els.append(exec_stack.push_bind(to_ctor=_errorhandling.ErrorHandlingToolUseExecutor, singleton=True))
63
62
 
64
- if cfg.dangerous_no_confirmation:
65
- els.append(exec_stack.push_bind(to_ctor=_rendering.ArgsRenderingToolUseExecutor, singleton=True))
63
+ if cfg.verbose:
64
+ els.append(exec_stack.push_bind(to_ctor=_rendering.ArgsRenderingToolUseExecutor, singleton=True))
65
+ els.append(exec_stack.push_bind(to_ctor=_rendering.ResultRenderingToolUseExecutor, singleton=True))
66
66
 
67
67
  els.extend([
68
68
  inj.bind(_execution.ToolUseExecutor, to_key=exec_stack.top),
@@ -70,11 +70,6 @@ def bind_tools(cfg: ToolsConfig = ToolsConfig()) -> inj.Elements:
70
70
 
71
71
  #
72
72
 
73
- if not cfg.dangerous_no_confirmation:
74
- els.append(inj.bind(_confirmation.ToolExecutionConfirmation, to_ctor=_confirmation.InteractiveToolExecutionConfirmation, singleton=True)) # noqa
75
-
76
- #
77
-
78
73
  els.extend([
79
74
  tool_context_providers().bind_items_provider(singleton=True),
80
75
 
@@ -4,7 +4,7 @@ from omlish import dataclasses as dc
4
4
  from omlish import inject as inj
5
5
  from omlish import lang
6
6
 
7
- from ..... import minichain as mc
7
+ from ...... import minichain as mc
8
8
  from .configs import ToolSetConfig
9
9
 
10
10
 
@@ -29,10 +29,10 @@ def tool_context_providers() -> 'inj.ItemsBinderHelper[_execution.ToolContextPro
29
29
 
30
30
 
31
31
  def bind_tool_context_provider_to_key(key: ta.Any) -> inj.Elements:
32
- return tool_context_providers().bind_item(to_fn=inj.KwargsTarget.of(
33
- lambda v: _execution.ToolContextProvider(lambda: [v]),
34
- v=key,
35
- ), singleton=True)
32
+ return tool_context_providers().bind_item(
33
+ to_fn=inj.target(v=key)(lambda v: _execution.ToolContextProvider(lambda: [v])),
34
+ singleton=True,
35
+ )
36
36
 
37
37
 
38
38
  ##
@@ -1,8 +1,8 @@
1
1
  import typing as ta
2
2
 
3
- from ..... import minichain as mc
4
- from ....rendering.types import ContentRendering
5
- from .execution import ToolUseExecutor
3
+ from ...... import minichain as mc
4
+ from .....rendering.types import ContentRendering
5
+ from ...drivers.tools.execution import ToolUseExecutor
6
6
 
7
7
 
8
8
  ##
@@ -10,9 +10,9 @@ from .configs import TodoToolSetConfig
10
10
 
11
11
 
12
12
  def bind_todo_tools(cfg: TodoToolSetConfig) -> inj.Elements:
13
- from ......minichain.lib.todo.context import TodoContext
14
- from ......minichain.lib.todo.tools.read import todo_read_tool
15
- from ......minichain.lib.todo.tools.write import todo_write_tool
13
+ from .......minichain.lib.todo.context import TodoContext
14
+ from .......minichain.lib.todo.tools.read import todo_read_tool
15
+ from .......minichain.lib.todo.tools.write import todo_write_tool
16
16
 
17
17
  return inj.as_elements(
18
18
  tool_catalog_entries().bind_item_consts(
@@ -1,4 +1,4 @@
1
- from ...... import minichain as mc
1
+ from ....... import minichain as mc
2
2
 
3
3
 
4
4
  ##
@@ -0,0 +1,31 @@
1
+ import abc
2
+ import typing as ta
3
+ import uuid
4
+
5
+ from omlish import lang
6
+ from omlish import typedvalues as tv
7
+
8
+ from ..... import minichain as mc
9
+
10
+
11
+ ##
12
+
13
+
14
+ class ChatDriverId(tv.UniqueScalarTypedValue[uuid.UUID]):
15
+ pass
16
+
17
+
18
+ class ChatDriverGetter(lang.Func0[ta.Awaitable['ChatDriver']]):
19
+ pass
20
+
21
+
22
+ class ChatDriver(lang.Abstract):
23
+ async def start(self) -> None:
24
+ pass
25
+
26
+ async def stop(self) -> None:
27
+ pass
28
+
29
+ @abc.abstractmethod
30
+ def send_user_messages(self, next_user_chat: 'mc.UserChat') -> ta.Awaitable[None]:
31
+ raise NotImplementedError
@@ -12,6 +12,3 @@ from ...... import minichain as mc
12
12
  class UserConfig:
13
13
  initial_system_content: ta.Optional['mc.Content'] = None
14
14
  initial_user_content: ta.Optional['mc.Content'] = None
15
-
16
- interactive: bool = False
17
- use_readline: bool | ta.Literal['auto'] = 'auto'
@@ -0,0 +1,41 @@
1
+ from omlish import check
2
+ from omlish import inject as inj
3
+ from omlish import lang
4
+
5
+ from ...... import minichain as mc
6
+ from ..phases.injection import phase_callbacks
7
+ from ..phases.types import ChatPhase
8
+ from ..phases.types import ChatPhaseCallback
9
+ from .configs import UserConfig
10
+
11
+
12
+ with lang.auto_proxy_import(globals()):
13
+ from .. import types as _driver
14
+ from ..state import types as _state
15
+
16
+
17
+ ##
18
+
19
+
20
+ def bind_user(cfg: UserConfig = UserConfig()) -> inj.Elements:
21
+ els: list[inj.Elemental] = []
22
+
23
+ if cfg.initial_system_content is not None:
24
+ async def add_initial_system_content(cm: '_state.ChatStateManager') -> None:
25
+ await cm.extend_chat([mc.SystemMessage(check.not_none(cfg.initial_system_content))])
26
+
27
+ els.append(phase_callbacks().bind_item(to_fn=inj.KwargsTarget.of(
28
+ lambda cm: ChatPhaseCallback(ChatPhase.STARTED, lambda: add_initial_system_content(cm)),
29
+ cm=_state.ChatStateManager,
30
+ )))
31
+
32
+ if cfg.initial_user_content is not None:
33
+ async def add_initial_user_content(cdg: '_driver.ChatDriverGetter') -> None:
34
+ await (await cdg()).send_user_messages([mc.UserMessage(check.not_none(cfg.initial_user_content))])
35
+
36
+ els.append(phase_callbacks().bind_item(to_fn=inj.KwargsTarget.of(
37
+ lambda cdg: ChatPhaseCallback(ChatPhase.STARTED, lambda: add_initial_user_content(cdg)),
38
+ cdg=_driver.ChatDriverGetter,
39
+ )))
40
+
41
+ return inj.as_elements(*els)
File without changes
File without changes
@@ -0,0 +1,83 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+ from omlish import dataclasses as dc
5
+ from omlish import lang
6
+ from omlish.argparse import all as argparse
7
+
8
+
9
+ ##
10
+
11
+
12
+ class CommandError(Exception):
13
+ pass
14
+
15
+
16
+ @dc.dataclass()
17
+ class ArgsCommandError(CommandError):
18
+ command: 'Command'
19
+ argv: ta.Sequence[str]
20
+ help: str
21
+
22
+ arg_error: argparse.ArgumentError | None = None
23
+
24
+
25
+ ##
26
+
27
+
28
+ class Command(lang.Abstract):
29
+ def __init__(self) -> None:
30
+ super().__init__()
31
+
32
+ self.__parser: argparse.ArgumentParser = argparse.NoExitArgumentParser(
33
+ prog=self.name,
34
+ description=self.description,
35
+ formatter_class=self._HelpFormatter,
36
+ )
37
+ self._configure_parser(self.__parser)
38
+
39
+ #
40
+
41
+ @property
42
+ def name(self) -> str:
43
+ return lang.camel_to_snake(type(self).__name__.removesuffix('Command'))
44
+
45
+ @property
46
+ def description(self) -> str | None:
47
+ return None
48
+
49
+ class _HelpFormatter(argparse.HelpFormatter):
50
+ def start_section(self, heading):
51
+ return super().start_section(heading.title())
52
+
53
+ def add_usage(self, usage, actions, groups, prefix=None):
54
+ if prefix is None:
55
+ prefix = 'Usage: '
56
+ return super().add_usage(usage, actions, groups, prefix)
57
+
58
+ def _configure_parser(self, parser: argparse.ArgumentParser) -> None:
59
+ pass
60
+
61
+ #
62
+
63
+ @dc.dataclass(frozen=True, kw_only=True)
64
+ class Context:
65
+ print: ta.Callable[[str], ta.Awaitable[None]]
66
+
67
+ @ta.final
68
+ async def run(self, ctx: Context, argv: list[str]) -> None:
69
+ try:
70
+ args = self.__parser.parse_args(argv)
71
+ except argparse.ArgumentError as ae:
72
+ raise ArgsCommandError(
73
+ self,
74
+ argv,
75
+ self.__parser.format_help(),
76
+ ae,
77
+ ) from ae
78
+
79
+ await self._run_args(ctx, args)
80
+
81
+ @abc.abstractmethod
82
+ def _run_args(self, ctx: Context, args: argparse.Namespace) -> ta.Awaitable[None]:
83
+ raise NotImplementedError
@@ -0,0 +1,9 @@
1
+ from omlish import dataclasses as dc
2
+
3
+
4
+ ##
5
+
6
+
7
+ @dc.dataclass(frozen=True, kw_only=True)
8
+ class CommandsConfig:
9
+ pass
@@ -0,0 +1,41 @@
1
+ from omlish import inject as inj
2
+ from omlish import lang
3
+
4
+ from .configs import CommandsConfig
5
+ from .injection import commands
6
+
7
+
8
+ with lang.auto_proxy_import(globals()):
9
+ from . import manager as _manager
10
+ from . import simple as _simple
11
+
12
+
13
+ ##
14
+
15
+
16
+ def bind_commands(cfg: CommandsConfig = CommandsConfig()) -> inj.Elements:
17
+ els: list[inj.Elemental] = []
18
+
19
+ #
20
+
21
+ els.append(commands().bind_items_provider(singleton=True))
22
+
23
+ #
24
+
25
+ els.extend([
26
+ inj.bind(_manager.CommandsManager, singleton=True),
27
+ ])
28
+
29
+ #
30
+
31
+ els.extend([
32
+ inj.bind(_simple.EchoCommand, singleton=True),
33
+ commands().bind_item(to_key=_simple.EchoCommand),
34
+
35
+ inj.bind(_simple.QuitCommand, singleton=True),
36
+ commands().bind_item(to_key=_simple.QuitCommand),
37
+ ])
38
+
39
+ #
40
+
41
+ return inj.as_elements(*els)
@@ -0,0 +1,15 @@
1
+ from omlish import inject as inj
2
+ from omlish import lang
3
+
4
+
5
+ with lang.auto_proxy_import(globals()):
6
+ from . import base as _base
7
+ from . import types as _types
8
+
9
+
10
+ ##
11
+
12
+
13
+ @lang.cached_function
14
+ def commands() -> 'inj.ItemsBinderHelper[_base.Command]':
15
+ return inj.items_binder_helper[_base.Command](_types.Commands)
@@ -0,0 +1,59 @@
1
+ import enum
2
+ import shlex
3
+
4
+ from omlish import collections as col
5
+
6
+ from ..ui import UiMessageDisplayer
7
+ from .base import Command
8
+ from .types import Commands
9
+
10
+
11
+ ##
12
+
13
+
14
+ class RunCommandResult(enum.StrEnum):
15
+ SUCCESS = 'success'
16
+ FAILURE = 'failure'
17
+
18
+
19
+ class CommandsManager:
20
+ def __init__(
21
+ self,
22
+ *,
23
+ commands: Commands,
24
+ ui_message_displayer: UiMessageDisplayer,
25
+ ) -> None:
26
+ super().__init__()
27
+
28
+ self._commands = commands
29
+ self._ui_message_displayer = ui_message_displayer
30
+
31
+ self._commands_by_name = col.make_map((
32
+ (c.name, c) for c in commands
33
+ ), strict=True)
34
+
35
+ async def run_command_text(self, text: str) -> RunCommandResult:
36
+ try:
37
+ parts = shlex.split(text)
38
+ except ValueError as e:
39
+ await self._ui_message_displayer.display_ui_message(f'Invalid command syntax: {e}')
40
+ return RunCommandResult.FAILURE
41
+
42
+ if not parts:
43
+ return RunCommandResult.FAILURE
44
+
45
+ cmd = parts[0].lstrip('/').lower()
46
+ argv = parts[1:]
47
+
48
+ command = self._commands_by_name.get(cmd)
49
+ if not command:
50
+ await self._ui_message_displayer.display_ui_message(f'Unknown command: {cmd}')
51
+ return RunCommandResult.FAILURE
52
+
53
+ ctx = Command.Context(
54
+ print=self._ui_message_displayer.display_ui_message,
55
+ )
56
+
57
+ await command.run(ctx, argv)
58
+
59
+ return RunCommandResult.SUCCESS
@@ -0,0 +1,34 @@
1
+ from omlish.argparse import all as argparse
2
+
3
+ from ..ui import UiQuitSignal
4
+ from .base import Command
5
+
6
+
7
+ ##
8
+
9
+
10
+ class EchoCommand(Command):
11
+ def _configure_parser(self, parser: argparse.ArgumentParser) -> None:
12
+ super()._configure_parser(parser)
13
+
14
+ parser.add_argument('message', help='Message to echo')
15
+
16
+ async def _run_args(self, ctx: Command.Context, args: argparse.Namespace) -> None:
17
+ await ctx.print(args.message)
18
+
19
+
20
+ ##
21
+
22
+
23
+ class QuitCommand(Command):
24
+ def __init__(
25
+ self,
26
+ *,
27
+ quit_signal: UiQuitSignal,
28
+ ) -> None:
29
+ super().__init__()
30
+
31
+ self._quit_signal = quit_signal
32
+
33
+ async def _run_args(self, ctx: Command.Context, args: argparse.Namespace) -> None:
34
+ await self._quit_signal()
@@ -0,0 +1,13 @@
1
+ import typing as ta
2
+
3
+ from omlish import lang
4
+
5
+
6
+ with lang.auto_proxy_import(globals()):
7
+ from . import base as _base
8
+
9
+
10
+ ##
11
+
12
+
13
+ Commands = ta.NewType('Commands', ta.Sequence['_base.Command'])
@@ -0,0 +1,11 @@
1
+ from omlish import dataclasses as dc
2
+
3
+ from .commands.configs import CommandsConfig
4
+
5
+
6
+ ##
7
+
8
+
9
+ @dc.dataclass(frozen=True, kw_only=True)
10
+ class FacadeConfig:
11
+ commands: CommandsConfig = CommandsConfig()
@@ -0,0 +1,26 @@
1
+ from ..... import minichain as mc
2
+ from ..drivers.types import ChatDriver
3
+ from .commands.manager import CommandsManager
4
+
5
+
6
+ ##
7
+
8
+
9
+ class ChatFacade:
10
+ def __init__(
11
+ self,
12
+ *,
13
+ driver: ChatDriver,
14
+ commands: CommandsManager,
15
+ ) -> None:
16
+ super().__init__()
17
+
18
+ self._driver = driver
19
+ self._commands = commands
20
+
21
+ async def handle_user_input(self, text: str) -> None:
22
+ if text.startswith('/'):
23
+ await self._commands.run_command_text(text[1:])
24
+
25
+ else:
26
+ await self._driver.send_user_messages([mc.UserMessage(text)])