ommlds 0.0.0.dev436__py3-none-any.whl → 0.0.0.dev480__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 (271) hide show
  1. ommlds/.omlish-manifests.json +332 -35
  2. ommlds/__about__.py +15 -9
  3. ommlds/_hacks/__init__.py +4 -0
  4. ommlds/_hacks/funcs.py +110 -0
  5. ommlds/_hacks/names.py +158 -0
  6. ommlds/_hacks/params.py +73 -0
  7. ommlds/_hacks/patches.py +0 -3
  8. ommlds/backends/anthropic/protocol/_marshal.py +2 -2
  9. ommlds/backends/anthropic/protocol/sse/_marshal.py +1 -1
  10. ommlds/backends/anthropic/protocol/sse/assemble.py +23 -7
  11. ommlds/backends/anthropic/protocol/sse/events.py +13 -0
  12. ommlds/backends/anthropic/protocol/types.py +30 -9
  13. ommlds/backends/google/protocol/__init__.py +3 -0
  14. ommlds/backends/google/protocol/_marshal.py +16 -0
  15. ommlds/backends/google/protocol/types.py +626 -0
  16. ommlds/backends/groq/_marshal.py +23 -0
  17. ommlds/backends/groq/protocol.py +249 -0
  18. ommlds/backends/mlx/generation.py +1 -1
  19. ommlds/backends/mlx/loading.py +58 -1
  20. ommlds/backends/ollama/__init__.py +0 -0
  21. ommlds/backends/ollama/protocol.py +170 -0
  22. ommlds/backends/openai/protocol/__init__.py +9 -28
  23. ommlds/backends/openai/protocol/_common.py +18 -0
  24. ommlds/backends/openai/protocol/_marshal.py +27 -0
  25. ommlds/backends/openai/protocol/chatcompletion/chunk.py +58 -31
  26. ommlds/backends/openai/protocol/chatcompletion/contentpart.py +49 -44
  27. ommlds/backends/openai/protocol/chatcompletion/message.py +55 -43
  28. ommlds/backends/openai/protocol/chatcompletion/request.py +114 -66
  29. ommlds/backends/openai/protocol/chatcompletion/response.py +71 -45
  30. ommlds/backends/openai/protocol/chatcompletion/responseformat.py +27 -20
  31. ommlds/backends/openai/protocol/chatcompletion/tokenlogprob.py +16 -7
  32. ommlds/backends/openai/protocol/completionusage.py +24 -15
  33. ommlds/backends/tavily/__init__.py +0 -0
  34. ommlds/backends/tavily/protocol.py +301 -0
  35. ommlds/backends/tinygrad/models/llama3/__init__.py +22 -14
  36. ommlds/backends/transformers/__init__.py +0 -0
  37. ommlds/backends/transformers/filecache.py +109 -0
  38. ommlds/backends/transformers/streamers.py +73 -0
  39. ommlds/cli/asyncs.py +30 -0
  40. ommlds/cli/backends/catalog.py +93 -0
  41. ommlds/cli/backends/configs.py +9 -0
  42. ommlds/cli/backends/inject.py +31 -36
  43. ommlds/cli/backends/injection.py +16 -0
  44. ommlds/cli/backends/types.py +46 -0
  45. ommlds/cli/content/__init__.py +0 -0
  46. ommlds/cli/content/messages.py +34 -0
  47. ommlds/cli/content/strings.py +42 -0
  48. ommlds/cli/inject.py +15 -32
  49. ommlds/cli/inputs/__init__.py +0 -0
  50. ommlds/cli/inputs/asyncs.py +32 -0
  51. ommlds/cli/inputs/sync.py +75 -0
  52. ommlds/cli/main.py +270 -110
  53. ommlds/cli/rendering/__init__.py +0 -0
  54. ommlds/cli/rendering/configs.py +9 -0
  55. ommlds/cli/rendering/inject.py +31 -0
  56. ommlds/cli/rendering/markdown.py +52 -0
  57. ommlds/cli/rendering/raw.py +73 -0
  58. ommlds/cli/rendering/types.py +21 -0
  59. ommlds/cli/secrets.py +21 -0
  60. ommlds/cli/sessions/base.py +1 -1
  61. ommlds/cli/sessions/chat/chat/__init__.py +0 -0
  62. ommlds/cli/sessions/chat/chat/ai/__init__.py +0 -0
  63. ommlds/cli/sessions/chat/chat/ai/configs.py +11 -0
  64. ommlds/cli/sessions/chat/chat/ai/inject.py +74 -0
  65. ommlds/cli/sessions/chat/chat/ai/injection.py +14 -0
  66. ommlds/cli/sessions/chat/chat/ai/rendering.py +70 -0
  67. ommlds/cli/sessions/chat/chat/ai/services.py +79 -0
  68. ommlds/cli/sessions/chat/chat/ai/tools.py +44 -0
  69. ommlds/cli/sessions/chat/chat/ai/types.py +28 -0
  70. ommlds/cli/sessions/chat/chat/state/__init__.py +0 -0
  71. ommlds/cli/sessions/chat/chat/state/configs.py +11 -0
  72. ommlds/cli/sessions/chat/chat/state/inject.py +36 -0
  73. ommlds/cli/sessions/chat/chat/state/inmemory.py +33 -0
  74. ommlds/cli/sessions/chat/chat/state/storage.py +52 -0
  75. ommlds/cli/sessions/chat/chat/state/types.py +38 -0
  76. ommlds/cli/sessions/chat/chat/user/__init__.py +0 -0
  77. ommlds/cli/sessions/chat/chat/user/configs.py +17 -0
  78. ommlds/cli/sessions/chat/chat/user/inject.py +62 -0
  79. ommlds/cli/sessions/chat/chat/user/interactive.py +31 -0
  80. ommlds/cli/sessions/chat/chat/user/oneshot.py +25 -0
  81. ommlds/cli/sessions/chat/chat/user/types.py +15 -0
  82. ommlds/cli/sessions/chat/configs.py +27 -0
  83. ommlds/cli/sessions/chat/driver.py +43 -0
  84. ommlds/cli/sessions/chat/inject.py +33 -65
  85. ommlds/cli/sessions/chat/phases/__init__.py +0 -0
  86. ommlds/cli/sessions/chat/phases/inject.py +27 -0
  87. ommlds/cli/sessions/chat/phases/injection.py +14 -0
  88. ommlds/cli/sessions/chat/phases/manager.py +29 -0
  89. ommlds/cli/sessions/chat/phases/types.py +29 -0
  90. ommlds/cli/sessions/chat/session.py +27 -0
  91. ommlds/cli/sessions/chat/tools/__init__.py +0 -0
  92. ommlds/cli/sessions/chat/tools/configs.py +22 -0
  93. ommlds/cli/sessions/chat/tools/confirmation.py +46 -0
  94. ommlds/cli/sessions/chat/tools/execution.py +66 -0
  95. ommlds/cli/sessions/chat/tools/fs/__init__.py +0 -0
  96. ommlds/cli/sessions/chat/tools/fs/configs.py +12 -0
  97. ommlds/cli/sessions/chat/tools/fs/inject.py +35 -0
  98. ommlds/cli/sessions/chat/tools/inject.py +88 -0
  99. ommlds/cli/sessions/chat/tools/injection.py +44 -0
  100. ommlds/cli/sessions/chat/tools/rendering.py +58 -0
  101. ommlds/cli/sessions/chat/tools/todo/__init__.py +0 -0
  102. ommlds/cli/sessions/chat/tools/todo/configs.py +12 -0
  103. ommlds/cli/sessions/chat/tools/todo/inject.py +31 -0
  104. ommlds/cli/sessions/chat/tools/weather/__init__.py +0 -0
  105. ommlds/cli/sessions/chat/tools/weather/configs.py +12 -0
  106. ommlds/cli/sessions/chat/tools/weather/inject.py +22 -0
  107. ommlds/cli/{tools/weather.py → sessions/chat/tools/weather/tools.py} +1 -1
  108. ommlds/cli/sessions/completion/configs.py +21 -0
  109. ommlds/cli/sessions/completion/inject.py +42 -0
  110. ommlds/cli/sessions/completion/session.py +35 -0
  111. ommlds/cli/sessions/embedding/configs.py +21 -0
  112. ommlds/cli/sessions/embedding/inject.py +42 -0
  113. ommlds/cli/sessions/embedding/session.py +33 -0
  114. ommlds/cli/sessions/inject.py +28 -11
  115. ommlds/cli/state/__init__.py +0 -0
  116. ommlds/cli/state/inject.py +28 -0
  117. ommlds/cli/{state.py → state/storage.py} +41 -24
  118. ommlds/minichain/__init__.py +84 -24
  119. ommlds/minichain/_marshal.py +49 -9
  120. ommlds/minichain/_typedvalues.py +2 -4
  121. ommlds/minichain/backends/catalogs/base.py +20 -1
  122. ommlds/minichain/backends/catalogs/simple.py +2 -2
  123. ommlds/minichain/backends/catalogs/strings.py +10 -8
  124. ommlds/minichain/backends/impls/anthropic/chat.py +65 -27
  125. ommlds/minichain/backends/impls/anthropic/names.py +10 -8
  126. ommlds/minichain/backends/impls/anthropic/protocol.py +109 -0
  127. ommlds/minichain/backends/impls/anthropic/stream.py +111 -43
  128. ommlds/minichain/backends/impls/duckduckgo/search.py +1 -1
  129. ommlds/minichain/backends/impls/dummy/__init__.py +0 -0
  130. ommlds/minichain/backends/impls/dummy/chat.py +69 -0
  131. ommlds/minichain/backends/impls/google/chat.py +114 -22
  132. ommlds/minichain/backends/impls/google/search.py +7 -2
  133. ommlds/minichain/backends/impls/google/stream.py +219 -0
  134. ommlds/minichain/backends/impls/google/tools.py +149 -0
  135. ommlds/minichain/backends/impls/groq/__init__.py +0 -0
  136. ommlds/minichain/backends/impls/groq/chat.py +75 -0
  137. ommlds/minichain/backends/impls/groq/names.py +48 -0
  138. ommlds/minichain/backends/impls/groq/protocol.py +143 -0
  139. ommlds/minichain/backends/impls/groq/stream.py +125 -0
  140. ommlds/minichain/backends/impls/llamacpp/chat.py +33 -18
  141. ommlds/minichain/backends/impls/llamacpp/completion.py +1 -1
  142. ommlds/minichain/backends/impls/llamacpp/format.py +4 -2
  143. ommlds/minichain/backends/impls/llamacpp/stream.py +37 -20
  144. ommlds/minichain/backends/impls/mistral.py +20 -5
  145. ommlds/minichain/backends/impls/mlx/chat.py +96 -22
  146. ommlds/minichain/backends/impls/ollama/__init__.py +0 -0
  147. ommlds/minichain/backends/impls/ollama/chat.py +199 -0
  148. ommlds/minichain/backends/impls/openai/chat.py +18 -8
  149. ommlds/minichain/backends/impls/openai/completion.py +10 -3
  150. ommlds/minichain/backends/impls/openai/embedding.py +10 -3
  151. ommlds/minichain/backends/impls/openai/format.py +131 -106
  152. ommlds/minichain/backends/impls/openai/names.py +31 -5
  153. ommlds/minichain/backends/impls/openai/stream.py +43 -25
  154. ommlds/minichain/backends/impls/tavily.py +66 -0
  155. ommlds/minichain/backends/impls/tinygrad/chat.py +23 -16
  156. ommlds/minichain/backends/impls/transformers/sentence.py +1 -1
  157. ommlds/minichain/backends/impls/transformers/tokens.py +1 -1
  158. ommlds/minichain/backends/impls/transformers/transformers.py +155 -34
  159. ommlds/minichain/backends/strings/parsing.py +1 -1
  160. ommlds/minichain/backends/strings/resolving.py +4 -1
  161. ommlds/minichain/chat/_marshal.py +16 -9
  162. ommlds/minichain/chat/choices/adapters.py +4 -4
  163. ommlds/minichain/chat/choices/services.py +1 -1
  164. ommlds/minichain/chat/choices/stream/__init__.py +0 -0
  165. ommlds/minichain/chat/choices/stream/adapters.py +35 -0
  166. ommlds/minichain/chat/choices/stream/joining.py +31 -0
  167. ommlds/minichain/chat/choices/stream/services.py +45 -0
  168. ommlds/minichain/chat/choices/stream/types.py +43 -0
  169. ommlds/minichain/chat/choices/types.py +2 -2
  170. ommlds/minichain/chat/history.py +3 -3
  171. ommlds/minichain/chat/messages.py +55 -19
  172. ommlds/minichain/chat/services.py +3 -3
  173. ommlds/minichain/chat/stream/_marshal.py +16 -0
  174. ommlds/minichain/chat/stream/joining.py +85 -0
  175. ommlds/minichain/chat/stream/services.py +15 -21
  176. ommlds/minichain/chat/stream/types.py +32 -19
  177. ommlds/minichain/chat/tools/execution.py +8 -7
  178. ommlds/minichain/chat/tools/ids.py +9 -15
  179. ommlds/minichain/chat/tools/parsing.py +17 -26
  180. ommlds/minichain/chat/transforms/base.py +29 -38
  181. ommlds/minichain/chat/transforms/metadata.py +30 -4
  182. ommlds/minichain/chat/transforms/services.py +9 -11
  183. ommlds/minichain/content/_marshal.py +44 -20
  184. ommlds/minichain/content/json.py +13 -0
  185. ommlds/minichain/content/materialize.py +14 -21
  186. ommlds/minichain/content/prepare.py +4 -0
  187. ommlds/minichain/content/transforms/interleave.py +1 -1
  188. ommlds/minichain/content/transforms/squeeze.py +1 -1
  189. ommlds/minichain/content/transforms/stringify.py +1 -1
  190. ommlds/minichain/json.py +20 -0
  191. ommlds/minichain/lib/code/__init__.py +0 -0
  192. ommlds/minichain/lib/code/prompts.py +6 -0
  193. ommlds/minichain/lib/fs/binfiles.py +108 -0
  194. ommlds/minichain/lib/fs/context.py +126 -0
  195. ommlds/minichain/lib/fs/errors.py +101 -0
  196. ommlds/minichain/lib/fs/suggestions.py +36 -0
  197. ommlds/minichain/lib/fs/tools/__init__.py +0 -0
  198. ommlds/minichain/lib/fs/tools/edit.py +104 -0
  199. ommlds/minichain/lib/fs/tools/ls.py +38 -0
  200. ommlds/minichain/lib/fs/tools/read.py +115 -0
  201. ommlds/minichain/lib/fs/tools/recursivels/__init__.py +0 -0
  202. ommlds/minichain/lib/fs/tools/recursivels/execution.py +40 -0
  203. ommlds/minichain/lib/todo/__init__.py +0 -0
  204. ommlds/minichain/lib/todo/context.py +54 -0
  205. ommlds/minichain/lib/todo/tools/__init__.py +0 -0
  206. ommlds/minichain/lib/todo/tools/read.py +44 -0
  207. ommlds/minichain/lib/todo/tools/write.py +335 -0
  208. ommlds/minichain/lib/todo/types.py +60 -0
  209. ommlds/minichain/llms/_marshal.py +25 -17
  210. ommlds/minichain/llms/types.py +4 -0
  211. ommlds/minichain/registries/globals.py +18 -4
  212. ommlds/minichain/resources.py +66 -43
  213. ommlds/minichain/search.py +1 -1
  214. ommlds/minichain/services/_marshal.py +46 -39
  215. ommlds/minichain/services/facades.py +3 -3
  216. ommlds/minichain/services/services.py +1 -1
  217. ommlds/minichain/standard.py +8 -0
  218. ommlds/minichain/stream/services.py +152 -38
  219. ommlds/minichain/stream/wrap.py +22 -24
  220. ommlds/minichain/tools/_marshal.py +1 -1
  221. ommlds/minichain/tools/execution/catalog.py +2 -1
  222. ommlds/minichain/tools/execution/context.py +34 -14
  223. ommlds/minichain/tools/execution/errors.py +15 -0
  224. ommlds/minichain/tools/execution/executors.py +8 -3
  225. ommlds/minichain/tools/execution/reflect.py +40 -5
  226. ommlds/minichain/tools/fns.py +46 -9
  227. ommlds/minichain/tools/jsonschema.py +14 -5
  228. ommlds/minichain/tools/reflect.py +54 -18
  229. ommlds/minichain/tools/types.py +33 -1
  230. ommlds/minichain/utils.py +27 -0
  231. ommlds/minichain/vectors/_marshal.py +11 -10
  232. ommlds/nanochat/LICENSE +21 -0
  233. ommlds/nanochat/__init__.py +0 -0
  234. ommlds/nanochat/rustbpe/LICENSE +21 -0
  235. ommlds/nanochat/tokenizers.py +406 -0
  236. ommlds/server/server.py +3 -3
  237. ommlds/specs/__init__.py +0 -0
  238. ommlds/specs/mcp/__init__.py +0 -0
  239. ommlds/specs/mcp/_marshal.py +23 -0
  240. ommlds/specs/mcp/protocol.py +266 -0
  241. ommlds/tools/git.py +27 -10
  242. ommlds/tools/ocr.py +8 -9
  243. ommlds/wiki/analyze.py +2 -2
  244. ommlds/wiki/text/mfh.py +1 -5
  245. ommlds/wiki/text/wtp.py +1 -3
  246. ommlds/wiki/utils/xml.py +5 -5
  247. {ommlds-0.0.0.dev436.dist-info → ommlds-0.0.0.dev480.dist-info}/METADATA +24 -21
  248. ommlds-0.0.0.dev480.dist-info/RECORD +427 -0
  249. ommlds/cli/backends/standard.py +0 -20
  250. ommlds/cli/sessions/chat/base.py +0 -42
  251. ommlds/cli/sessions/chat/interactive.py +0 -73
  252. ommlds/cli/sessions/chat/printing.py +0 -96
  253. ommlds/cli/sessions/chat/prompt.py +0 -143
  254. ommlds/cli/sessions/chat/state.py +0 -109
  255. ommlds/cli/sessions/chat/tools.py +0 -91
  256. ommlds/cli/sessions/completion/completion.py +0 -44
  257. ommlds/cli/sessions/embedding/embedding.py +0 -42
  258. ommlds/cli/tools/config.py +0 -13
  259. ommlds/cli/tools/inject.py +0 -64
  260. ommlds/minichain/chat/stream/adapters.py +0 -69
  261. ommlds/minichain/lib/fs/ls/execution.py +0 -32
  262. ommlds-0.0.0.dev436.dist-info/RECORD +0 -303
  263. /ommlds/{cli/tools → backends/google}/__init__.py +0 -0
  264. /ommlds/{minichain/lib/fs/ls → backends/groq}/__init__.py +0 -0
  265. /ommlds/{huggingface.py → backends/huggingface.py} +0 -0
  266. /ommlds/minichain/lib/fs/{ls → tools/recursivels}/rendering.py +0 -0
  267. /ommlds/minichain/lib/fs/{ls → tools/recursivels}/running.py +0 -0
  268. {ommlds-0.0.0.dev436.dist-info → ommlds-0.0.0.dev480.dist-info}/WHEEL +0 -0
  269. {ommlds-0.0.0.dev436.dist-info → ommlds-0.0.0.dev480.dist-info}/entry_points.txt +0 -0
  270. {ommlds-0.0.0.dev436.dist-info → ommlds-0.0.0.dev480.dist-info}/licenses/LICENSE +0 -0
  271. {ommlds-0.0.0.dev436.dist-info → ommlds-0.0.0.dev480.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,25 @@
1
+ import typing as ta
2
+
3
+ from ...... import minichain as mc
4
+ from .types import UserChatInput
5
+
6
+
7
+ ##
8
+
9
+
10
+ OneshotUserChatInputInitialChat = ta.NewType('OneshotUserChatInputInitialChat', mc.UserChat)
11
+
12
+
13
+ class OneshotUserChatInput(UserChatInput):
14
+ def __init__(
15
+ self,
16
+ initial_chat: OneshotUserChatInputInitialChat,
17
+ ) -> None:
18
+ super().__init__()
19
+
20
+ self._pending_chat: mc.UserChat | None = initial_chat
21
+
22
+ async def get_next_user_messages(self) -> 'mc.UserChat':
23
+ ret = self._pending_chat
24
+ self._pending_chat = None
25
+ return ret or []
@@ -0,0 +1,15 @@
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 UserChatInput(lang.Abstract):
13
+ @abc.abstractmethod
14
+ def get_next_user_messages(self) -> ta.Awaitable['mc.UserChat']:
15
+ raise NotImplementedError
@@ -0,0 +1,27 @@
1
+ from omlish import dataclasses as dc
2
+
3
+ from ...backends.configs import BackendConfig
4
+ from ...rendering.configs import RenderingConfig
5
+ from .chat.ai.configs import AiConfig
6
+ from .chat.state.configs import StateConfig
7
+ from .chat.user.configs import UserConfig
8
+ from .tools.configs import ToolsConfig
9
+
10
+
11
+ ##
12
+
13
+
14
+ DEFAULT_BACKEND = 'openai'
15
+
16
+
17
+ ##
18
+
19
+
20
+ @dc.dataclass(frozen=True, kw_only=True)
21
+ class ChatConfig:
22
+ backend: BackendConfig = BackendConfig()
23
+ ai: AiConfig = AiConfig()
24
+ state: StateConfig = StateConfig()
25
+ user: UserConfig = UserConfig()
26
+ rendering: RenderingConfig = RenderingConfig()
27
+ tools: ToolsConfig = ToolsConfig()
@@ -0,0 +1,43 @@
1
+ from .chat.ai.types import AiChatGenerator
2
+ from .chat.state.types import ChatStateManager
3
+ from .chat.user.types import UserChatInput
4
+ from .phases.manager import ChatPhaseManager
5
+ from .phases.types import ChatPhase
6
+
7
+
8
+ ##
9
+
10
+
11
+ class ChatDriver:
12
+ def __init__(
13
+ self,
14
+ *,
15
+ phases: ChatPhaseManager,
16
+ ai_chat_generator: AiChatGenerator,
17
+ user_chat_input: UserChatInput,
18
+ chat_state_manager: ChatStateManager,
19
+ ):
20
+ super().__init__()
21
+
22
+ self._phases = phases
23
+ self._ai_chat_generator = ai_chat_generator
24
+ self._user_chat_input = user_chat_input
25
+ self._chat_state_manager = chat_state_manager
26
+
27
+ async def run(self) -> None:
28
+ await self._phases.set_phase(ChatPhase.STARTING)
29
+ await self._phases.set_phase(ChatPhase.STARTED)
30
+
31
+ while True:
32
+ next_user_chat = await self._user_chat_input.get_next_user_messages()
33
+ if not next_user_chat:
34
+ break
35
+
36
+ prev_user_chat = (await self._chat_state_manager.get_state()).chat
37
+
38
+ next_ai_chat = await self._ai_chat_generator.get_next_ai_messages([*prev_user_chat, *next_user_chat])
39
+
40
+ await self._chat_state_manager.extend_chat([*next_user_chat, *next_ai_chat])
41
+
42
+ await self._phases.set_phase(ChatPhase.STOPPING)
43
+ await self._phases.set_phase(ChatPhase.STOPPED)
@@ -1,97 +1,65 @@
1
- import typing as ta
2
-
3
1
  from omlish import dataclasses as dc
4
2
  from omlish import inject as inj
5
3
  from omlish import lang
6
4
 
7
- from .base import ChatOption
8
- from .base import ChatOptions
9
- from .base import ChatSession
10
- from .printing import ChatSessionPrinter
11
- from .printing import MarkdownStringChatSessionPrinter
12
- from .printing import SimpleStringChatSessionPrinter
13
- from .state import ChatStateManager
14
- from .state import StateStorageChatStateManager
15
- from .tools import AskingToolExecutionConfirmation
16
- from .tools import NopToolExecutionConfirmation
17
- from .tools import ToolExecRequestExecutor
18
- from .tools import ToolExecRequestExecutorImpl
19
- from .tools import ToolExecutionConfirmation
5
+ from ...backends.types import DefaultBackendName
6
+ from ..base import Session
7
+ from .configs import DEFAULT_BACKEND
8
+ from .configs import ChatConfig
9
+
10
+
11
+ with lang.auto_proxy_import(globals()):
12
+ from ...backends import inject as _backends
13
+ from ...rendering import inject as _rendering
14
+ from . import driver as _driver
15
+ from . import session as _session
16
+ from .chat.ai import inject as _chat_ai
17
+ from .chat.state import inject as _chat_state
18
+ from .chat.user import inject as _chat_user
19
+ from .phases import inject as _phases
20
+ from .tools import inject as _tools
20
21
 
21
22
 
22
23
  ##
23
24
 
24
25
 
25
- @dc.dataclass(frozen=True, eq=False)
26
- class _InjectedChatOptions:
27
- v: ChatOptions
26
+ def bind_chat(cfg: ChatConfig) -> inj.Elements:
27
+ els: list[inj.Elemental] = []
28
28
 
29
+ #
29
30
 
30
- def bind_chat_options(*cos: ChatOption) -> inj.Elements:
31
- return inj.bind_set_entry_const(ta.AbstractSet[_InjectedChatOptions], _InjectedChatOptions(ChatOptions(cos)))
31
+ els.extend([
32
+ _backends.bind_backends(cfg.backend),
32
33
 
34
+ _chat_ai.bind_ai(cfg.ai),
33
35
 
34
- ##
36
+ _chat_user.bind_user(cfg.user),
35
37
 
38
+ _chat_state.bind_state(cfg.state),
36
39
 
37
- def bind_chat_session(cfg: ChatSession.Config) -> inj.Elements:
38
- els: list[inj.Elemental] = []
40
+ _phases.bind_phases(),
39
41
 
40
- #
42
+ _rendering.bind_rendering(cfg.rendering),
41
43
 
42
- els.extend([
43
- inj.set_binder[_InjectedChatOptions](),
44
- inj.bind(
45
- lang.typed_lambda(ChatOptions, s=ta.AbstractSet[_InjectedChatOptions])(
46
- lambda s: ChatOptions([
47
- co
48
- for ico in s
49
- for co in ico.v
50
- ]),
51
- ),
52
- singleton=True,
53
- ),
44
+ _tools.bind_tools(cfg.tools),
54
45
  ])
55
46
 
56
47
  #
57
48
 
58
49
  els.extend([
59
- inj.bind(StateStorageChatStateManager, singleton=True),
60
- inj.bind(ChatStateManager, to_key=StateStorageChatStateManager),
50
+ inj.bind(_driver.ChatDriver, singleton=True),
61
51
  ])
62
52
 
63
53
  #
64
54
 
65
- if cfg.markdown:
66
- els.extend([
67
- inj.bind(MarkdownStringChatSessionPrinter, singleton=True),
68
- inj.bind(ChatSessionPrinter, to_key=MarkdownStringChatSessionPrinter),
69
- ])
70
- else:
71
- els.extend([
72
- inj.bind(SimpleStringChatSessionPrinter, singleton=True),
73
- inj.bind(ChatSessionPrinter, to_key=SimpleStringChatSessionPrinter),
74
- ])
75
-
76
- #
77
-
78
- if cfg.dangerous_no_tool_confirmation:
79
- els.extend([
80
- inj.bind(NopToolExecutionConfirmation, singleton=True),
81
- inj.bind(ToolExecutionConfirmation, to_key=NopToolExecutionConfirmation),
82
- ])
83
- else:
84
- els.extend([
85
- inj.bind(AskingToolExecutionConfirmation, singleton=True),
86
- inj.bind(ToolExecutionConfirmation, to_key=AskingToolExecutionConfirmation),
87
- ])
55
+ els.extend([
56
+ inj.bind(_session.ChatSession.Config(**dc.asdict(cfg))),
57
+ inj.bind(Session, to_ctor=_session.ChatSession, singleton=True),
58
+ ])
88
59
 
89
60
  #
90
61
 
91
- els.extend([
92
- inj.bind(ToolExecRequestExecutorImpl, singleton=True),
93
- inj.bind(ToolExecRequestExecutor, to_key=ToolExecRequestExecutorImpl),
94
- ])
62
+ els.append(inj.bind(DefaultBackendName, to_const=DEFAULT_BACKEND))
95
63
 
96
64
  #
97
65
 
File without changes
@@ -0,0 +1,27 @@
1
+ from omlish import inject as inj
2
+ from omlish import lang
3
+
4
+ from .injection import phase_callbacks
5
+
6
+
7
+ with lang.auto_proxy_import(globals()):
8
+ from . import manager as _manager
9
+
10
+
11
+ ##
12
+
13
+
14
+ def bind_phases() -> inj.Elements:
15
+ els: list[inj.Elemental] = []
16
+
17
+ #
18
+
19
+ els.append(phase_callbacks().bind_items_provider(singleton=True))
20
+
21
+ #
22
+
23
+ els.append(inj.bind(_manager.ChatPhaseManager, singleton=True))
24
+
25
+ #
26
+
27
+ return inj.as_elements(*els)
@@ -0,0 +1,14 @@
1
+ from omlish import inject as inj
2
+ from omlish import lang
3
+
4
+
5
+ with lang.auto_proxy_import(globals()):
6
+ from . import types as _types
7
+
8
+
9
+ ##
10
+
11
+
12
+ @lang.cached_function
13
+ def phase_callbacks() -> 'inj.ItemsBinderHelper[_types.ChatPhaseCallback]':
14
+ return inj.items_binder_helper[_types.ChatPhaseCallback](_types.ChatPhaseCallbacks)
@@ -0,0 +1,29 @@
1
+ from omlish import check
2
+ from omlish import collections as col
3
+
4
+ from .types import ChatPhase
5
+ from .types import ChatPhaseCallbacks
6
+
7
+
8
+ ##
9
+
10
+
11
+ class ChatPhaseManager:
12
+ def __init__(self, callbacks: ChatPhaseCallbacks) -> None:
13
+ super().__init__()
14
+
15
+ self._callbacks = callbacks
16
+ self._callbacks_by_phase = col.multi_map_by(lambda cb: cb.phase, callbacks)
17
+
18
+ check.state(not self._callbacks_by_phase.get(ChatPhase.NEW))
19
+
20
+ self._phase = ChatPhase.NEW
21
+
22
+ @property
23
+ def phase(self) -> ChatPhase:
24
+ return self._phase
25
+
26
+ async def set_phase(self, phase: ChatPhase) -> None:
27
+ self._phase = phase
28
+ for cb in self._callbacks_by_phase.get(phase, ()):
29
+ await cb.fn()
@@ -0,0 +1,29 @@
1
+ import enum
2
+ import typing as ta
3
+
4
+ from omlish import dataclasses as dc
5
+
6
+
7
+ ##
8
+
9
+
10
+ class ChatPhase(enum.Enum):
11
+ NEW = enum.auto()
12
+
13
+ STARTING = enum.auto()
14
+ STARTED = enum.auto()
15
+
16
+ STOPPING = enum.auto()
17
+ STOPPED = enum.auto()
18
+
19
+
20
+ ##
21
+
22
+
23
+ @dc.dataclass(frozen=True)
24
+ class ChatPhaseCallback:
25
+ phase: ChatPhase = dc.xfield(validate=lambda v: v != ChatPhase.NEW)
26
+ fn: ta.Callable[[], ta.Awaitable[None]] = dc.xfield()
27
+
28
+
29
+ ChatPhaseCallbacks = ta.NewType('ChatPhaseCallbacks', ta.Sequence[ChatPhaseCallback])
@@ -0,0 +1,27 @@
1
+ from omlish import dataclasses as dc
2
+
3
+ from ..base import Session
4
+ from .configs import ChatConfig
5
+ from .driver import ChatDriver
6
+
7
+
8
+ ##
9
+
10
+
11
+ class ChatSession(Session['ChatSession.Config']):
12
+ @dc.dataclass(frozen=True)
13
+ class Config(Session.Config, ChatConfig):
14
+ pass
15
+
16
+ def __init__(
17
+ self,
18
+ config: Config,
19
+ *,
20
+ driver: ChatDriver,
21
+ ) -> None:
22
+ super().__init__(config)
23
+
24
+ self._driver = driver
25
+
26
+ async def run(self) -> None:
27
+ await self._driver.run()
File without changes
@@ -0,0 +1,22 @@
1
+ import typing as ta
2
+
3
+ from omlish import dataclasses as dc
4
+ from omlish import lang
5
+
6
+
7
+ ##
8
+
9
+
10
+ @dc.dataclass(frozen=True, kw_only=True)
11
+ class ToolsConfig:
12
+ silent: bool = False
13
+ dangerous_no_confirmation: bool = False
14
+ enabled_tools: ta.Iterable[str] | None = None
15
+
16
+
17
+ ##
18
+
19
+
20
+ @dc.dataclass(frozen=True, kw_only=True)
21
+ class ToolSetConfig(lang.Abstract):
22
+ pass
@@ -0,0 +1,46 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+ from omlish import lang
5
+ from omlish.formats import json
6
+ from omlish.term.confirm import confirm_action
7
+
8
+ from ..... import minichain as mc
9
+
10
+
11
+ ##
12
+
13
+
14
+ class ToolExecutionRequestDeniedError(Exception):
15
+ pass
16
+
17
+
18
+ class ToolExecutionConfirmation(lang.Abstract):
19
+ @abc.abstractmethod
20
+ def confirm_tool_execution_or_raise(
21
+ self,
22
+ use: 'mc.ToolUse',
23
+ entry: 'mc.ToolCatalogEntry',
24
+ ) -> ta.Awaitable[None]:
25
+ raise NotImplementedError
26
+
27
+
28
+ ##
29
+
30
+
31
+ class InteractiveToolExecutionConfirmation(ToolExecutionConfirmation):
32
+ async def confirm_tool_execution_or_raise(
33
+ self,
34
+ use: 'mc.ToolUse',
35
+ entry: 'mc.ToolCatalogEntry',
36
+ ) -> None:
37
+ tr_dct = dict(
38
+ id=use.id,
39
+ name=entry.spec.name,
40
+ args=use.args,
41
+ # spec=msh.marshal(tce.spec),
42
+ )
43
+ cr = confirm_action(f'Execute requested tool?\n\n{json.dumps_pretty(tr_dct)}') # FIXME: async lol
44
+
45
+ if not cr:
46
+ raise ToolExecutionRequestDeniedError
@@ -0,0 +1,66 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+ from omlish import check
5
+ from omlish import lang
6
+
7
+ from ..... import minichain as mc
8
+ from .confirmation import ToolExecutionConfirmation
9
+
10
+
11
+ ##
12
+
13
+
14
+ class ToolContextProvider(lang.Func0[ta.Sequence[ta.Any]]):
15
+ pass
16
+
17
+
18
+ ToolContextProviders = ta.NewType('ToolContextProviders', ta.Sequence[ToolContextProvider])
19
+
20
+
21
+ ##
22
+
23
+
24
+ class ToolUseExecutor(lang.Abstract):
25
+ @abc.abstractmethod
26
+ def execute_tool_use(
27
+ self,
28
+ use: 'mc.ToolUse',
29
+ *ctx_items: ta.Any,
30
+ ) -> ta.Awaitable['mc.ToolUseResultMessage']:
31
+ raise NotImplementedError
32
+
33
+
34
+ class ToolUseExecutorImpl(ToolUseExecutor):
35
+ def __init__(
36
+ self,
37
+ *,
38
+ catalog: 'mc.ToolCatalog',
39
+ ctx_provider: ToolContextProvider,
40
+ confirmation: ToolExecutionConfirmation | None = None,
41
+ ) -> None:
42
+ super().__init__()
43
+
44
+ self._catalog = catalog
45
+ self._ctx_provider = ctx_provider
46
+ self._confirmation = confirmation
47
+
48
+ async def execute_tool_use(
49
+ self,
50
+ use: 'mc.ToolUse',
51
+ *ctx_items: ta.Any,
52
+ ) -> 'mc.ToolUseResultMessage':
53
+ tce = self._catalog.by_name[check.non_empty_str(use.name)]
54
+
55
+ if self._confirmation is not None:
56
+ await self._confirmation.confirm_tool_execution_or_raise(use, tce)
57
+
58
+ return await mc.execute_tool_use(
59
+ mc.ToolContext(
60
+ use,
61
+ *self._ctx_provider(),
62
+ *ctx_items,
63
+ ),
64
+ tce.executor(),
65
+ use,
66
+ )
File without changes
@@ -0,0 +1,12 @@
1
+ from omlish import dataclasses as dc
2
+ from omlish import lang
3
+
4
+ from ..configs import ToolSetConfig
5
+
6
+
7
+ ##
8
+
9
+
10
+ @dc.dataclass(frozen=True, kw_only=True)
11
+ class FsToolSetConfig(ToolSetConfig, lang.Final):
12
+ pass
@@ -0,0 +1,35 @@
1
+ import os
2
+
3
+ from omlish import inject as inj
4
+
5
+ from ..injection import ToolSetBinder
6
+ from ..injection import bind_tool_context_provider_to_key
7
+ from ..injection import tool_catalog_entries
8
+ from .configs import FsToolSetConfig
9
+
10
+
11
+ ##
12
+
13
+
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
18
+
19
+ return inj.as_elements(
20
+ tool_catalog_entries().bind_item_consts(
21
+ ls_tool(),
22
+ read_tool(),
23
+ ),
24
+
25
+ inj.bind(FsContext(
26
+ root_dir=os.getcwd(),
27
+ )),
28
+ bind_tool_context_provider_to_key(FsContext),
29
+ )
30
+
31
+
32
+ ##
33
+
34
+
35
+ FS_TOOL_SET_BINDER = ToolSetBinder(FsToolSetConfig, bind_fs_tools)
@@ -0,0 +1,88 @@
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 .configs import ToolsConfig
7
+ from .injection import ToolSetBinder
8
+ from .injection import tool_catalog_entries
9
+ from .injection import tool_context_providers
10
+
11
+
12
+ with lang.auto_proxy_import(globals()):
13
+ from . import confirmation as _confirmation
14
+ from . import execution as _execution
15
+ from . import rendering as _rendering
16
+
17
+
18
+ ##
19
+
20
+
21
+ # if tools_config.enable_unsafe_tools_do_not_use_lol:
22
+ # from ...minichain.lib.bash import bash_tool
23
+ # els.append(bind_tool(bash_tool()))
24
+ #
25
+ # from ...minichain.lib.fs.tools.edit import edit_tool
26
+ # els.append(bind_tool(edit_tool()))
27
+
28
+
29
+ ##
30
+
31
+
32
+ def bind_tools(cfg: ToolsConfig = ToolsConfig()) -> inj.Elements:
33
+ els: list[inj.Elemental] = []
34
+
35
+ #
36
+
37
+ els.append(inj.bind(mc.ToolCatalog, singleton=True))
38
+
39
+ #
40
+
41
+ els.append(tool_catalog_entries().bind_items_provider(singleton=True))
42
+
43
+ for etn in check.not_isinstance(cfg.enabled_tools or [], str):
44
+ from .fs.inject import FS_TOOL_SET_BINDER
45
+ from .todo.inject import TODO_TOOL_SET_BINDER
46
+ from .weather.inject import WEATHER_TOOL_SET_BINDER
47
+ ts_binder: ToolSetBinder = { # type: ignore[assignment] # FIXME: placeholder obviously lol
48
+ 'fs': FS_TOOL_SET_BINDER,
49
+ 'todo': TODO_TOOL_SET_BINDER,
50
+ 'weather': WEATHER_TOOL_SET_BINDER,
51
+ }[etn]
52
+
53
+ els.append(ts_binder.fn(ts_binder.cfg_cls()))
54
+
55
+ #
56
+
57
+ exec_stack = inj.wrapper_binder_helper(_execution.ToolUseExecutor)
58
+
59
+ els.append(exec_stack.push_bind(to_ctor=_execution.ToolUseExecutorImpl, singleton=True))
60
+
61
+ if not cfg.silent:
62
+ els.append(exec_stack.push_bind(to_ctor=_rendering.ResultRenderingToolUseExecutor, singleton=True))
63
+
64
+ if cfg.dangerous_no_confirmation:
65
+ els.append(exec_stack.push_bind(to_ctor=_rendering.ArgsRenderingToolUseExecutor, singleton=True))
66
+
67
+ els.extend([
68
+ inj.bind(_execution.ToolUseExecutor, to_key=exec_stack.top),
69
+ ])
70
+
71
+ #
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
+ els.extend([
79
+ tool_context_providers().bind_items_provider(singleton=True),
80
+
81
+ inj.bind(_execution.ToolContextProvider, to_fn=lang.typed_lambda(tcps=_execution.ToolContextProviders)(
82
+ lambda tcps: _execution.ToolContextProvider(lambda: [tc for tcp in tcps for tc in tcp()]),
83
+ ), singleton=True),
84
+ ])
85
+
86
+ #
87
+
88
+ return inj.as_elements(*els)