ommlds 0.0.0.dev466__py3-none-any.whl → 0.0.0.dev512__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 (367) hide show
  1. ommlds/.omlish-manifests.json +404 -31
  2. ommlds/README.md +11 -0
  3. ommlds/__about__.py +21 -12
  4. ommlds/_hacks/__init__.py +4 -0
  5. ommlds/_hacks/funcs.py +110 -0
  6. ommlds/_hacks/names.py +158 -0
  7. ommlds/_hacks/params.py +73 -0
  8. ommlds/_hacks/patches.py +0 -3
  9. ommlds/backends/anthropic/protocol/__init__.py +13 -1
  10. ommlds/backends/anthropic/protocol/_dataclasses.py +1625 -0
  11. ommlds/backends/anthropic/protocol/sse/events.py +2 -0
  12. ommlds/backends/anthropic/protocol/types.py +5 -7
  13. ommlds/backends/cerebras/__init__.py +7 -0
  14. ommlds/backends/cerebras/_dataclasses.py +4254 -0
  15. ommlds/backends/cerebras/_marshal.py +24 -0
  16. ommlds/backends/cerebras/clients.py +9 -0
  17. ommlds/backends/cerebras/protocol.py +310 -0
  18. ommlds/backends/google/protocol/__init__.py +13 -0
  19. ommlds/backends/google/protocol/_dataclasses.py +5997 -0
  20. ommlds/backends/google/protocol/types.py +6 -8
  21. ommlds/backends/groq/__init__.py +7 -0
  22. ommlds/backends/groq/_dataclasses.py +3901 -0
  23. ommlds/backends/groq/_marshal.py +23 -0
  24. ommlds/backends/groq/clients.py +9 -0
  25. ommlds/backends/groq/protocol.py +247 -0
  26. ommlds/{huggingface.py → backends/huggingface/cache.py} +1 -6
  27. ommlds/backends/huggingface/cli.py +208 -0
  28. ommlds/backends/llamacpp/logging.py +4 -1
  29. ommlds/backends/mlx/caching.py +7 -3
  30. ommlds/backends/mlx/cli.py +10 -7
  31. ommlds/backends/mlx/generation.py +18 -16
  32. ommlds/backends/mlx/limits.py +10 -6
  33. ommlds/backends/mlx/loading.py +7 -4
  34. ommlds/backends/ollama/__init__.py +7 -0
  35. ommlds/backends/ollama/_dataclasses.py +3940 -0
  36. ommlds/backends/ollama/cli.py +36 -0
  37. ommlds/backends/ollama/protocol.py +201 -0
  38. ommlds/backends/openai/protocol/__init__.py +15 -1
  39. ommlds/backends/openai/protocol/_common.py +3 -5
  40. ommlds/backends/openai/protocol/_dataclasses.py +7708 -0
  41. ommlds/backends/tavily/__init__.py +7 -0
  42. ommlds/backends/tavily/_dataclasses.py +1734 -0
  43. ommlds/backends/tavily/protocol.py +299 -0
  44. ommlds/backends/tinygrad/models/llama3/__init__.py +22 -14
  45. ommlds/backends/torch/backends.py +1 -1
  46. ommlds/backends/transformers/__init__.py +14 -0
  47. ommlds/backends/transformers/filecache.py +109 -0
  48. ommlds/backends/transformers/streamers.py +73 -0
  49. ommlds/cli/__init__.py +7 -0
  50. ommlds/cli/_dataclasses.py +3835 -0
  51. ommlds/cli/asyncs.py +30 -0
  52. ommlds/cli/backends/catalog.py +88 -0
  53. ommlds/cli/backends/configs.py +9 -0
  54. ommlds/cli/backends/inject.py +100 -42
  55. ommlds/cli/{sessions/chat/backends → backends}/injection.py +1 -1
  56. ommlds/cli/backends/meta.py +82 -0
  57. ommlds/cli/{sessions/chat/backends → backends}/types.py +11 -1
  58. ommlds/cli/{sessions/chat/content → content}/messages.py +2 -2
  59. ommlds/cli/{sessions/chat/content → content}/strings.py +1 -1
  60. ommlds/cli/inject.py +17 -8
  61. ommlds/cli/inputs/asyncs.py +32 -0
  62. ommlds/cli/inputs/sync.py +75 -0
  63. ommlds/cli/main.py +346 -114
  64. ommlds/cli/rendering/configs.py +9 -0
  65. ommlds/cli/{sessions/chat/rendering → rendering}/inject.py +4 -5
  66. ommlds/cli/{sessions/chat/rendering → rendering}/markdown.py +1 -1
  67. ommlds/cli/{sessions/chat/rendering → rendering}/raw.py +1 -1
  68. ommlds/cli/{sessions/chat/rendering → rendering}/types.py +7 -1
  69. ommlds/cli/secrets.py +22 -0
  70. ommlds/cli/sessions/base.py +1 -10
  71. ommlds/cli/sessions/chat/configs.py +13 -30
  72. ommlds/cli/sessions/chat/drivers/ai/configs.py +13 -0
  73. ommlds/cli/sessions/chat/drivers/ai/events.py +57 -0
  74. ommlds/cli/sessions/chat/{chat → drivers}/ai/inject.py +15 -12
  75. ommlds/cli/sessions/chat/{chat → drivers}/ai/rendering.py +8 -8
  76. ommlds/cli/sessions/chat/{chat → drivers}/ai/services.py +5 -5
  77. ommlds/cli/sessions/chat/{chat → drivers}/ai/tools.py +4 -8
  78. ommlds/cli/sessions/chat/{chat → drivers}/ai/types.py +10 -1
  79. ommlds/cli/sessions/chat/drivers/configs.py +25 -0
  80. ommlds/cli/sessions/chat/drivers/events/inject.py +27 -0
  81. ommlds/cli/sessions/chat/drivers/events/injection.py +14 -0
  82. ommlds/cli/sessions/chat/drivers/events/manager.py +16 -0
  83. ommlds/cli/sessions/chat/drivers/events/types.py +44 -0
  84. ommlds/cli/sessions/chat/drivers/impl.py +50 -0
  85. ommlds/cli/sessions/chat/drivers/inject.py +70 -0
  86. ommlds/cli/sessions/chat/drivers/state/configs.py +13 -0
  87. ommlds/cli/sessions/chat/drivers/state/ids.py +25 -0
  88. ommlds/cli/sessions/chat/drivers/state/inject.py +83 -0
  89. ommlds/cli/sessions/chat/{chat → drivers}/state/inmemory.py +1 -6
  90. ommlds/cli/sessions/chat/{chat → drivers}/state/storage.py +18 -12
  91. ommlds/cli/sessions/chat/{chat → drivers}/state/types.py +11 -6
  92. ommlds/cli/sessions/chat/drivers/tools/configs.py +22 -0
  93. ommlds/cli/sessions/chat/drivers/tools/confirmation.py +44 -0
  94. ommlds/cli/sessions/chat/drivers/tools/errorhandling.py +39 -0
  95. ommlds/cli/sessions/chat/{tools → drivers/tools}/execution.py +3 -4
  96. ommlds/cli/sessions/chat/drivers/tools/fs/__init__.py +0 -0
  97. ommlds/cli/sessions/chat/drivers/tools/fs/configs.py +12 -0
  98. ommlds/cli/sessions/chat/drivers/tools/fs/inject.py +35 -0
  99. ommlds/cli/sessions/chat/drivers/tools/inject.py +83 -0
  100. ommlds/cli/sessions/chat/{tools → drivers/tools}/injection.py +20 -5
  101. ommlds/cli/sessions/chat/{tools → drivers/tools}/rendering.py +3 -3
  102. ommlds/cli/sessions/chat/drivers/tools/todo/__init__.py +0 -0
  103. ommlds/cli/sessions/chat/drivers/tools/todo/configs.py +12 -0
  104. ommlds/cli/sessions/chat/drivers/tools/todo/inject.py +31 -0
  105. ommlds/cli/sessions/chat/drivers/tools/weather/__init__.py +0 -0
  106. ommlds/cli/sessions/chat/drivers/tools/weather/configs.py +12 -0
  107. ommlds/cli/sessions/chat/drivers/tools/weather/inject.py +22 -0
  108. ommlds/cli/sessions/chat/{tools/weather.py → drivers/tools/weather/tools.py} +1 -1
  109. ommlds/cli/sessions/chat/drivers/types.py +31 -0
  110. ommlds/cli/sessions/chat/drivers/user/__init__.py +0 -0
  111. ommlds/cli/sessions/chat/drivers/user/configs.py +14 -0
  112. ommlds/cli/sessions/chat/drivers/user/inject.py +41 -0
  113. ommlds/cli/sessions/chat/facades/__init__.py +0 -0
  114. ommlds/cli/sessions/chat/facades/commands/__init__.py +0 -0
  115. ommlds/cli/sessions/chat/facades/commands/base.py +83 -0
  116. ommlds/cli/sessions/chat/facades/commands/configs.py +9 -0
  117. ommlds/cli/sessions/chat/facades/commands/inject.py +41 -0
  118. ommlds/cli/sessions/chat/facades/commands/injection.py +15 -0
  119. ommlds/cli/sessions/chat/facades/commands/manager.py +59 -0
  120. ommlds/cli/sessions/chat/facades/commands/simple.py +34 -0
  121. ommlds/cli/sessions/chat/facades/commands/types.py +13 -0
  122. ommlds/cli/sessions/chat/facades/configs.py +11 -0
  123. ommlds/cli/sessions/chat/facades/facade.py +26 -0
  124. ommlds/cli/sessions/chat/facades/inject.py +35 -0
  125. ommlds/cli/sessions/chat/facades/ui.py +34 -0
  126. ommlds/cli/sessions/chat/inject.py +10 -49
  127. ommlds/cli/sessions/chat/interfaces/__init__.py +0 -0
  128. ommlds/cli/sessions/chat/interfaces/bare/__init__.py +0 -0
  129. ommlds/cli/sessions/chat/interfaces/bare/configs.py +15 -0
  130. ommlds/cli/sessions/chat/interfaces/bare/inject.py +69 -0
  131. ommlds/cli/sessions/chat/interfaces/bare/interactive.py +49 -0
  132. ommlds/cli/sessions/chat/interfaces/bare/oneshot.py +21 -0
  133. ommlds/cli/sessions/chat/{tools/confirmation.py → interfaces/bare/tools.py} +3 -22
  134. ommlds/cli/sessions/chat/interfaces/base.py +13 -0
  135. ommlds/cli/sessions/chat/interfaces/configs.py +11 -0
  136. ommlds/cli/sessions/chat/interfaces/inject.py +29 -0
  137. ommlds/cli/sessions/chat/interfaces/textual/__init__.py +0 -0
  138. ommlds/cli/sessions/chat/interfaces/textual/app.py +429 -0
  139. ommlds/cli/sessions/chat/interfaces/textual/configs.py +11 -0
  140. ommlds/cli/sessions/chat/interfaces/textual/facades.py +19 -0
  141. ommlds/cli/sessions/chat/interfaces/textual/inject.py +111 -0
  142. ommlds/cli/sessions/chat/interfaces/textual/inputhistory.py +174 -0
  143. ommlds/cli/sessions/chat/interfaces/textual/interface.py +24 -0
  144. ommlds/cli/sessions/chat/interfaces/textual/styles/__init__.py +29 -0
  145. ommlds/cli/sessions/chat/interfaces/textual/styles/input.tcss +53 -0
  146. ommlds/cli/sessions/chat/interfaces/textual/styles/markdown.tcss +7 -0
  147. ommlds/cli/sessions/chat/interfaces/textual/styles/messages.tcss +167 -0
  148. ommlds/cli/sessions/chat/interfaces/textual/tools.py +38 -0
  149. ommlds/cli/sessions/chat/interfaces/textual/widgets/__init__.py +0 -0
  150. ommlds/cli/sessions/chat/interfaces/textual/widgets/input.py +70 -0
  151. ommlds/cli/sessions/chat/interfaces/textual/widgets/messages.py +207 -0
  152. ommlds/cli/sessions/chat/session.py +8 -13
  153. ommlds/cli/sessions/completion/configs.py +5 -6
  154. ommlds/cli/sessions/completion/inject.py +15 -2
  155. ommlds/cli/sessions/completion/session.py +10 -18
  156. ommlds/cli/sessions/configs.py +10 -0
  157. ommlds/cli/sessions/embedding/configs.py +5 -6
  158. ommlds/cli/sessions/embedding/inject.py +15 -2
  159. ommlds/cli/sessions/embedding/session.py +10 -18
  160. ommlds/cli/sessions/inject.py +15 -15
  161. ommlds/cli/state/storage.py +8 -2
  162. ommlds/minichain/__init__.py +217 -60
  163. ommlds/minichain/_dataclasses.py +20640 -0
  164. ommlds/minichain/_typedvalues.py +15 -8
  165. ommlds/minichain/backends/catalogs/base.py +20 -1
  166. ommlds/minichain/backends/catalogs/simple.py +2 -2
  167. ommlds/minichain/backends/catalogs/strings.py +13 -10
  168. ommlds/minichain/backends/impls/anthropic/chat.py +28 -5
  169. ommlds/minichain/backends/impls/anthropic/names.py +3 -3
  170. ommlds/minichain/backends/impls/anthropic/protocol.py +2 -2
  171. ommlds/minichain/backends/impls/anthropic/stream.py +23 -18
  172. ommlds/minichain/backends/impls/cerebras/__init__.py +0 -0
  173. ommlds/minichain/backends/impls/cerebras/chat.py +82 -0
  174. ommlds/minichain/backends/impls/cerebras/names.py +45 -0
  175. ommlds/minichain/backends/impls/cerebras/protocol.py +143 -0
  176. ommlds/minichain/backends/impls/cerebras/stream.py +114 -0
  177. ommlds/minichain/backends/impls/duckduckgo/search.py +5 -1
  178. ommlds/minichain/backends/impls/dummy/__init__.py +0 -0
  179. ommlds/minichain/backends/impls/dummy/chat.py +69 -0
  180. ommlds/minichain/backends/impls/google/chat.py +20 -84
  181. ommlds/minichain/backends/impls/google/names.py +6 -0
  182. ommlds/minichain/backends/impls/google/protocol.py +105 -0
  183. ommlds/minichain/backends/impls/google/search.py +10 -5
  184. ommlds/minichain/backends/impls/google/stream.py +64 -142
  185. ommlds/minichain/backends/impls/google/tools.py +2 -2
  186. ommlds/minichain/backends/impls/groq/__init__.py +0 -0
  187. ommlds/minichain/backends/impls/groq/chat.py +77 -0
  188. ommlds/minichain/backends/impls/groq/names.py +48 -0
  189. ommlds/minichain/backends/impls/groq/protocol.py +143 -0
  190. ommlds/minichain/backends/impls/groq/stream.py +114 -0
  191. ommlds/minichain/backends/impls/huggingface/repos.py +1 -5
  192. ommlds/minichain/backends/impls/llamacpp/chat.py +15 -3
  193. ommlds/minichain/backends/impls/llamacpp/completion.py +7 -3
  194. ommlds/minichain/backends/impls/llamacpp/stream.py +38 -19
  195. ommlds/minichain/backends/impls/mistral.py +9 -2
  196. ommlds/minichain/backends/impls/mlx/chat.py +100 -23
  197. ommlds/minichain/backends/impls/ollama/__init__.py +0 -0
  198. ommlds/minichain/backends/impls/ollama/chat.py +193 -0
  199. ommlds/minichain/backends/impls/ollama/protocol.py +144 -0
  200. ommlds/minichain/backends/impls/openai/chat.py +14 -7
  201. ommlds/minichain/backends/impls/openai/completion.py +9 -2
  202. ommlds/minichain/backends/impls/openai/embedding.py +9 -2
  203. ommlds/minichain/backends/impls/openai/format.py +117 -115
  204. ommlds/minichain/backends/impls/openai/names.py +33 -5
  205. ommlds/minichain/backends/impls/openai/stream.py +61 -70
  206. ommlds/minichain/backends/impls/sentencepiece/tokens.py +9 -6
  207. ommlds/minichain/backends/impls/tavily.py +66 -0
  208. ommlds/minichain/backends/impls/tinygrad/chat.py +17 -14
  209. ommlds/minichain/backends/impls/tokenizers/tokens.py +9 -6
  210. ommlds/minichain/backends/impls/transformers/sentence.py +5 -2
  211. ommlds/minichain/backends/impls/transformers/tokens.py +9 -6
  212. ommlds/minichain/backends/impls/transformers/transformers.py +139 -20
  213. ommlds/minichain/backends/strings/parsing.py +2 -2
  214. ommlds/minichain/backends/strings/resolving.py +7 -2
  215. ommlds/minichain/chat/choices/stream/__init__.py +0 -0
  216. ommlds/minichain/chat/{stream → choices/stream}/adapters.py +7 -7
  217. ommlds/minichain/chat/choices/stream/joining.py +31 -0
  218. ommlds/minichain/chat/choices/stream/services.py +45 -0
  219. ommlds/minichain/chat/choices/stream/types.py +43 -0
  220. ommlds/minichain/chat/content.py +42 -0
  221. ommlds/minichain/chat/messages.py +46 -42
  222. ommlds/minichain/chat/stream/_marshal.py +4 -4
  223. ommlds/minichain/chat/stream/joining.py +56 -43
  224. ommlds/minichain/chat/stream/services.py +15 -15
  225. ommlds/minichain/chat/stream/types.py +17 -24
  226. ommlds/minichain/chat/templating.py +3 -3
  227. ommlds/minichain/content/__init__.py +20 -3
  228. ommlds/minichain/content/_marshal.py +181 -55
  229. ommlds/minichain/content/code.py +26 -0
  230. ommlds/minichain/content/composite.py +28 -0
  231. ommlds/minichain/content/content.py +27 -0
  232. ommlds/minichain/content/dynamic.py +12 -0
  233. ommlds/minichain/content/emphasis.py +27 -0
  234. ommlds/minichain/content/images.py +2 -2
  235. ommlds/minichain/content/json.py +2 -2
  236. ommlds/minichain/content/link.py +13 -0
  237. ommlds/minichain/content/markdown.py +12 -0
  238. ommlds/minichain/content/metadata.py +10 -0
  239. ommlds/minichain/content/namespaces.py +8 -0
  240. ommlds/minichain/content/placeholders.py +10 -9
  241. ommlds/minichain/content/quote.py +26 -0
  242. ommlds/minichain/content/raw.py +49 -0
  243. ommlds/minichain/content/recursive.py +12 -0
  244. ommlds/minichain/content/resources.py +22 -0
  245. ommlds/minichain/content/section.py +26 -0
  246. ommlds/minichain/content/sequence.py +17 -3
  247. ommlds/minichain/content/standard.py +32 -0
  248. ommlds/minichain/content/tag.py +28 -0
  249. ommlds/minichain/content/templates.py +13 -0
  250. ommlds/minichain/content/text.py +2 -2
  251. ommlds/minichain/content/transform/__init__.py +0 -0
  252. ommlds/minichain/content/transform/json.py +55 -0
  253. ommlds/minichain/content/transform/markdown.py +8 -0
  254. ommlds/minichain/content/transform/materialize.py +59 -0
  255. ommlds/minichain/content/transform/metadata.py +16 -0
  256. ommlds/minichain/content/transform/namespaces.py +20 -0
  257. ommlds/minichain/content/transform/placeholders.py +60 -0
  258. ommlds/minichain/content/{prepare.py → transform/prepare.py} +10 -15
  259. ommlds/minichain/content/transform/recursive.py +54 -0
  260. ommlds/minichain/content/transform/resources.py +58 -0
  261. ommlds/minichain/content/transform/standard.py +43 -0
  262. ommlds/minichain/content/{transforms → transform}/stringify.py +1 -7
  263. ommlds/minichain/content/transform/strings.py +33 -0
  264. ommlds/minichain/content/transform/templates.py +25 -0
  265. ommlds/minichain/content/transform/types.py +18 -0
  266. ommlds/minichain/content/transform/visitors.py +38 -0
  267. ommlds/minichain/content/visitors.py +218 -0
  268. ommlds/minichain/http/__init__.py +0 -0
  269. ommlds/minichain/http/stream.py +195 -0
  270. ommlds/minichain/lib/fs/tools/read.py +1 -1
  271. ommlds/minichain/lib/fs/tools/recursivels/rendering.py +1 -1
  272. ommlds/minichain/lib/fs/tools/recursivels/running.py +1 -1
  273. ommlds/minichain/lib/todo/tools/write.py +2 -1
  274. ommlds/minichain/lib/todo/types.py +1 -1
  275. ommlds/minichain/llms/types.py +4 -0
  276. ommlds/minichain/metadata.py +56 -2
  277. ommlds/minichain/models/configs.py +2 -2
  278. ommlds/minichain/models/names.py +2 -0
  279. ommlds/minichain/registries/globals.py +18 -4
  280. ommlds/minichain/resources.py +49 -3
  281. ommlds/minichain/search.py +1 -1
  282. ommlds/minichain/services/README.md +154 -0
  283. ommlds/minichain/services/__init__.py +6 -2
  284. ommlds/minichain/services/_marshal.py +46 -10
  285. ommlds/minichain/services/_origclasses.py +11 -0
  286. ommlds/minichain/services/_typedvalues.py +8 -3
  287. ommlds/minichain/services/requests.py +73 -3
  288. ommlds/minichain/services/responses.py +73 -3
  289. ommlds/minichain/services/services.py +9 -0
  290. ommlds/minichain/standard.py +8 -0
  291. ommlds/minichain/stream/services.py +43 -17
  292. ommlds/minichain/text/applypatch.py +2 -1
  293. ommlds/minichain/text/toolparsing/llamacpp/types.py +1 -1
  294. ommlds/minichain/tokens/specials.py +1 -1
  295. ommlds/minichain/tools/execution/catalog.py +2 -2
  296. ommlds/minichain/tools/execution/errorhandling.py +36 -0
  297. ommlds/minichain/tools/execution/errors.py +2 -2
  298. ommlds/minichain/tools/execution/executors.py +1 -1
  299. ommlds/minichain/tools/fns.py +1 -1
  300. ommlds/minichain/tools/jsonschema.py +2 -2
  301. ommlds/minichain/tools/reflect.py +11 -7
  302. ommlds/minichain/tools/types.py +16 -19
  303. ommlds/minichain/vectors/_marshal.py +1 -1
  304. ommlds/minichain/vectors/embeddings.py +1 -1
  305. ommlds/minichain/wrappers/__init__.py +7 -0
  306. ommlds/minichain/wrappers/firstinwins.py +144 -0
  307. ommlds/minichain/wrappers/instrument.py +146 -0
  308. ommlds/minichain/wrappers/retry.py +168 -0
  309. ommlds/minichain/wrappers/services.py +98 -0
  310. ommlds/minichain/wrappers/stream.py +57 -0
  311. ommlds/nanochat/LICENSE +21 -0
  312. ommlds/nanochat/__init__.py +0 -0
  313. ommlds/nanochat/rustbpe/LICENSE +21 -0
  314. ommlds/nanochat/rustbpe/README.md +10 -0
  315. ommlds/nanochat/tokenizers.py +440 -0
  316. ommlds/specs/__init__.py +0 -0
  317. ommlds/specs/mcp/__init__.py +0 -0
  318. ommlds/specs/mcp/_marshal.py +23 -0
  319. ommlds/specs/mcp/clients.py +146 -0
  320. ommlds/specs/mcp/protocol.py +369 -0
  321. ommlds/tools/git.py +84 -64
  322. ommlds/tools/ocr.py +1 -1
  323. ommlds/wiki/analyze.py +2 -2
  324. ommlds/wiki/models.py +4 -4
  325. ommlds/wiki/text/mfh.py +9 -9
  326. ommlds/wiki/utils/xml.py +5 -5
  327. {ommlds-0.0.0.dev466.dist-info → ommlds-0.0.0.dev512.dist-info}/METADATA +28 -21
  328. ommlds-0.0.0.dev512.dist-info/RECORD +534 -0
  329. {ommlds-0.0.0.dev466.dist-info → ommlds-0.0.0.dev512.dist-info}/WHEEL +1 -1
  330. ommlds/cli/backends/standard.py +0 -20
  331. ommlds/cli/sessions/chat/backends/catalog.py +0 -56
  332. ommlds/cli/sessions/chat/backends/inject.py +0 -37
  333. ommlds/cli/sessions/chat/chat/state/inject.py +0 -40
  334. ommlds/cli/sessions/chat/chat/user/inject.py +0 -61
  335. ommlds/cli/sessions/chat/chat/user/interactive.py +0 -29
  336. ommlds/cli/sessions/chat/chat/user/oneshot.py +0 -25
  337. ommlds/cli/sessions/chat/chat/user/types.py +0 -15
  338. ommlds/cli/sessions/chat/driver.py +0 -43
  339. ommlds/cli/sessions/chat/tools/inject.py +0 -145
  340. ommlds/minichain/backends/impls/openai/format2.py +0 -210
  341. ommlds/minichain/content/materialize.py +0 -196
  342. ommlds/minichain/content/simple.py +0 -47
  343. ommlds/minichain/content/transforms/base.py +0 -46
  344. ommlds/minichain/content/transforms/interleave.py +0 -70
  345. ommlds/minichain/content/transforms/squeeze.py +0 -72
  346. ommlds/minichain/content/transforms/strings.py +0 -24
  347. ommlds/minichain/content/types.py +0 -43
  348. ommlds/minichain/stream/wrap.py +0 -62
  349. ommlds-0.0.0.dev466.dist-info/RECORD +0 -376
  350. /ommlds/{cli/sessions/chat/backends → backends/huggingface}/__init__.py +0 -0
  351. /ommlds/cli/{sessions/chat/chat → content}/__init__.py +0 -0
  352. /ommlds/cli/{sessions/chat/chat/ai → inputs}/__init__.py +0 -0
  353. /ommlds/cli/{sessions/chat/chat/state → rendering}/__init__.py +0 -0
  354. /ommlds/cli/sessions/chat/{chat/user → drivers}/__init__.py +0 -0
  355. /ommlds/cli/sessions/chat/{content → drivers/ai}/__init__.py +0 -0
  356. /ommlds/cli/sessions/chat/{chat → drivers}/ai/injection.py +0 -0
  357. /ommlds/cli/sessions/chat/{phases → drivers/events}/__init__.py +0 -0
  358. /ommlds/cli/sessions/chat/{rendering → drivers/phases}/__init__.py +0 -0
  359. /ommlds/cli/sessions/chat/{phases → drivers/phases}/inject.py +0 -0
  360. /ommlds/cli/sessions/chat/{phases → drivers/phases}/injection.py +0 -0
  361. /ommlds/cli/sessions/chat/{phases → drivers/phases}/manager.py +0 -0
  362. /ommlds/cli/sessions/chat/{phases → drivers/phases}/types.py +0 -0
  363. /ommlds/cli/sessions/chat/{tools → drivers/state}/__init__.py +0 -0
  364. /ommlds/{minichain/content/transforms → cli/sessions/chat/drivers/tools}/__init__.py +0 -0
  365. {ommlds-0.0.0.dev466.dist-info → ommlds-0.0.0.dev512.dist-info}/entry_points.txt +0 -0
  366. {ommlds-0.0.0.dev466.dist-info → ommlds-0.0.0.dev512.dist-info}/licenses/LICENSE +0 -0
  367. {ommlds-0.0.0.dev466.dist-info → ommlds-0.0.0.dev512.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,33 @@
1
+ import typing as ta
2
+
3
+ from omlish import dataclasses as dc
4
+
5
+ from ..content import Content
6
+ from ..emphasis import EmphasisContent
7
+ from ..metadata import ContentOriginal
8
+ from ..text import TextContent
9
+ from .visitors import VisitorContentTransform
10
+
11
+
12
+ T = ta.TypeVar('T')
13
+
14
+
15
+ ##
16
+
17
+
18
+ @dc.dataclass(frozen=True)
19
+ class StringFnContentTransform(VisitorContentTransform[None]):
20
+ fn: ta.Callable[[str], str]
21
+
22
+ def visit_str(self, c: str, ctx: None) -> TextContent:
23
+ return TextContent(self.fn(c)).with_metadata(ContentOriginal(c))
24
+
25
+ def visit_text_content(self, c: TextContent, ctx: None) -> TextContent:
26
+ return c.replace(s=self.fn(c.s))
27
+
28
+ def visit_emphasis_content(self, c: EmphasisContent, ctx: None) -> EmphasisContent:
29
+ return c.replace(s=self.fn(c.s))
30
+
31
+
32
+ def transform_content_strings(fn: ta.Callable[[str], str], o: Content) -> Content:
33
+ return StringFnContentTransform(fn).transform(o, None)
@@ -0,0 +1,25 @@
1
+ from omlish import check
2
+ from omlish.text import templating as tpl
3
+
4
+ from ..content import Content
5
+ from ..metadata import ContentOriginal
6
+ from ..templates import TemplateContent
7
+ from ..text import TextContent
8
+ from .visitors import VisitorContentTransform
9
+
10
+
11
+ ##
12
+
13
+
14
+ class TemplateContentMaterializer(VisitorContentTransform[None]):
15
+ def __init__(
16
+ self,
17
+ templater_context: tpl.Templater.Context | None = None,
18
+ ) -> None:
19
+ super().__init__()
20
+
21
+ self._templater_context = templater_context
22
+
23
+ def visit_template_content(self, c: TemplateContent, ctx: None) -> Content:
24
+ s = c.t.render(check.not_none(self._templater_context))
25
+ return TextContent(s).with_metadata(ContentOriginal(c))
@@ -0,0 +1,18 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+ from omlish import lang
5
+
6
+ from ..content import Content
7
+
8
+
9
+ C = ta.TypeVar('C')
10
+
11
+
12
+ ##
13
+
14
+
15
+ class ContentTransform(lang.Abstract, ta.Generic[C]):
16
+ @abc.abstractmethod
17
+ def transform(self, c: Content, ctx: C) -> Content:
18
+ raise NotImplementedError
@@ -0,0 +1,38 @@
1
+ import collections.abc
2
+ import typing as ta
3
+
4
+ from omlish import check
5
+ from omlish import lang
6
+
7
+ from ..composite import CompositeContent
8
+ from ..content import Content
9
+ from ..visitors import ContentVisitor
10
+ from .types import ContentTransform
11
+
12
+
13
+ C = ta.TypeVar('C')
14
+
15
+
16
+ ##
17
+
18
+
19
+ class VisitorContentTransform(ContentVisitor[C, Content], ContentTransform[C], lang.Abstract):
20
+ @ta.final
21
+ def transform(self, c: Content, ctx: C) -> Content:
22
+ """Final - must be identical to `visit`."""
23
+
24
+ return self.visit(c, ctx)
25
+
26
+ #
27
+
28
+ def visit_content(self, c: Content, ctx: C) -> Content:
29
+ return c
30
+
31
+ def visit_sequence(self, c: ta.Sequence[Content], ctx: C) -> Content:
32
+ return lang.map_preserve(lambda cc: self.visit(cc, ctx), c)
33
+
34
+ def visit_composite_content(self, c: CompositeContent, ctx: C) -> Content:
35
+ cc = c.child_content()
36
+ ncc = self.visit_sequence(cc, ctx)
37
+ nc = c.replace_child_content(check.isinstance(ncc, collections.abc.Sequence))
38
+ return super().visit_composite_content(nc, ctx)
@@ -0,0 +1,218 @@
1
+ import collections.abc
2
+ import inspect
3
+ import typing as ta
4
+
5
+ from omlish import collections as col
6
+ from omlish import lang
7
+
8
+ from .code import BlockCodeContent
9
+ from .code import CodeContent
10
+ from .code import InlineCodeContent
11
+ from .composite import CompositeContent
12
+ from .content import BaseContent
13
+ from .content import Content
14
+ from .dynamic import DynamicContent
15
+ from .emphasis import BoldContent
16
+ from .emphasis import BoldItalicContent
17
+ from .emphasis import EmphasisContent
18
+ from .emphasis import ItalicContent
19
+ from .images import ImageContent
20
+ from .json import JsonContent
21
+ from .link import LinkContent
22
+ from .markdown import MarkdownContent
23
+ from .namespaces import NamespaceContent
24
+ from .placeholders import PlaceholderContent
25
+ from .quote import QuoteContent
26
+ from .recursive import RecursiveContent
27
+ from .resources import ResourceContent
28
+ from .section import SectionContent
29
+ from .sequence import BlockContent
30
+ from .sequence import InlineContent
31
+ from .sequence import ItemListContent
32
+ from .sequence import SequenceContent
33
+ from .standard import StandardContent
34
+ from .tag import TagContent
35
+ from .templates import TemplateContent
36
+ from .text import TextContent
37
+
38
+
39
+ C = ta.TypeVar('C')
40
+ R = ta.TypeVar('R')
41
+
42
+
43
+ ##
44
+
45
+
46
+ class ContentVisitor(lang.Abstract, ta.Generic[C, R]):
47
+ _visit_method_map: ta.ClassVar[ta.Mapping[ta.Any, str]]
48
+
49
+ def visit(self, c: Content, ctx: C) -> R:
50
+ if isinstance(c, str):
51
+ return self.visit_str(c, ctx)
52
+
53
+ if isinstance(c, collections.abc.Sequence):
54
+ return self.visit_sequence(c, ctx)
55
+
56
+ try:
57
+ a = self._visit_method_map[type(c)]
58
+ except KeyError:
59
+ raise TypeError(c) from None
60
+
61
+ return getattr(self, a)(c, ctx)
62
+
63
+ ##
64
+ # per-type visit methods
65
+
66
+ def visit_content(self, c: Content, ctx: C) -> R:
67
+ raise TypeError(c)
68
+
69
+ ##
70
+ # non-BaseContent
71
+
72
+ def visit_str(self, c: str, ctx: C) -> R:
73
+ return self.visit_content(c, ctx)
74
+
75
+ def visit_sequence(self, c: ta.Sequence[Content], ctx: C) -> R:
76
+ return self.visit_content(c, ctx)
77
+
78
+ ##
79
+ # BaseContent
80
+
81
+ def visit_base_content(self, c: BaseContent, ctx: C) -> R:
82
+ return self.visit_content(c, ctx)
83
+
84
+ ##
85
+ # StandardContent
86
+
87
+ def visit_standard_content(self, c: StandardContent, ctx: C) -> R:
88
+ return self.visit_base_content(c, ctx)
89
+
90
+ ##
91
+ # leaf StandardContent
92
+
93
+ def visit_image_content(self, c: ImageContent, ctx: C) -> R:
94
+ return self.visit_standard_content(c, ctx)
95
+
96
+ def visit_json_content(self, c: JsonContent, ctx: C) -> R:
97
+ return self.visit_standard_content(c, ctx)
98
+
99
+ def visit_link_content(self, c: LinkContent, ctx: C) -> R:
100
+ return self.visit_standard_content(c, ctx)
101
+
102
+ def visit_markdown_content(self, c: MarkdownContent, ctx: C) -> R:
103
+ return self.visit_standard_content(c, ctx)
104
+
105
+ def visit_quote_content(self, c: QuoteContent, ctx: C) -> R:
106
+ return self.visit_standard_content(c, ctx)
107
+
108
+ def visit_text_content(self, c: TextContent, ctx: C) -> R:
109
+ return self.visit_standard_content(c, ctx)
110
+
111
+ ##
112
+ # CompositeContent
113
+
114
+ def visit_composite_content(self, c: CompositeContent, ctx: C) -> R:
115
+ return self.visit_standard_content(c, ctx)
116
+
117
+ def visit_section_content(self, c: SectionContent, ctx: C) -> R:
118
+ return self.visit_composite_content(c, ctx)
119
+
120
+ def visit_tag_content(self, c: TagContent, ctx: C) -> R:
121
+ return self.visit_composite_content(c, ctx)
122
+
123
+ ##
124
+ # CodeContent
125
+
126
+ def visit_code_content(self, c: CodeContent, ctx: C) -> R:
127
+ return self.visit_standard_content(c, ctx)
128
+
129
+ def visit_inline_code_content(self, c: InlineCodeContent, ctx: C) -> R:
130
+ return self.visit_code_content(c, ctx)
131
+
132
+ def visit_block_code_content(self, c: BlockCodeContent, ctx: C) -> R:
133
+ return self.visit_code_content(c, ctx)
134
+
135
+ ##
136
+ # DynamicContent
137
+
138
+ def visit_dynamic_content(self, c: DynamicContent, ctx: C) -> R:
139
+ return self.visit_standard_content(c, ctx)
140
+
141
+ def visit_recursive_content(self, c: RecursiveContent, ctx: C) -> R:
142
+ return self.visit_dynamic_content(c, ctx)
143
+
144
+ def visit_namespace_content(self, c: NamespaceContent, ctx: C) -> R:
145
+ return self.visit_recursive_content(c, ctx)
146
+
147
+ def visit_placeholder_content(self, c: PlaceholderContent, ctx: C) -> R:
148
+ return self.visit_recursive_content(c, ctx)
149
+
150
+ def visit_resource_content(self, c: ResourceContent, ctx: C) -> R:
151
+ return self.visit_recursive_content(c, ctx)
152
+
153
+ def visit_template_content(self, c: TemplateContent, ctx: C) -> R:
154
+ return self.visit_dynamic_content(c, ctx)
155
+
156
+ ##
157
+ # EmphasisContent
158
+
159
+ def visit_emphasis_content(self, c: EmphasisContent, ctx: C) -> R:
160
+ return self.visit_standard_content(c, ctx)
161
+
162
+ def visit_bold_content(self, c: BoldContent, ctx: C) -> R:
163
+ return self.visit_emphasis_content(c, ctx)
164
+
165
+ def visit_italic_content(self, c: ItalicContent, ctx: C) -> R:
166
+ return self.visit_emphasis_content(c, ctx)
167
+
168
+ def visit_bold_italic_content(self, c: BoldItalicContent, ctx: C) -> R:
169
+ return self.visit_emphasis_content(c, ctx)
170
+
171
+ ##
172
+ # SequenceContent
173
+
174
+ def visit_sequence_content(self, c: SequenceContent, ctx: C) -> R:
175
+ return self.visit_composite_content(c, ctx)
176
+
177
+ def visit_inline_content(self, c: InlineContent, ctx: C) -> R:
178
+ return self.visit_sequence_content(c, ctx)
179
+
180
+ def visit_block_content(self, c: BlockContent, ctx: C) -> R:
181
+ return self.visit_sequence_content(c, ctx)
182
+
183
+ def visit_item_list_content(self, c: ItemListContent, ctx: C) -> R:
184
+ return self.visit_sequence_content(c, ctx)
185
+
186
+
187
+ ContentVisitor._visit_method_map = col.make_map([ # noqa
188
+ (list(inspect.signature(o).parameters.values())[1].annotation, a)
189
+ for a, o in ContentVisitor.__dict__.items()
190
+ if a.startswith('visit_')
191
+ ], strict=True)
192
+
193
+
194
+ ##
195
+
196
+
197
+ class StandardContentVisitorTypeError(TypeError):
198
+ pass
199
+
200
+
201
+ class StandardContentVisitor(ContentVisitor[C, R], lang.Abstract):
202
+ def visit_str(self, c: str, ctx: C) -> R:
203
+ raise StandardContentVisitorTypeError(c)
204
+
205
+ def visit_sequence(self, c: ta.Sequence[Content], ctx: C) -> R:
206
+ raise StandardContentVisitorTypeError(c)
207
+
208
+
209
+ ##
210
+
211
+
212
+ class StaticContentVisitorTypeError(TypeError):
213
+ pass
214
+
215
+
216
+ class StaticContentVisitor(ContentVisitor[C, R], lang.Abstract):
217
+ def visit_dynamic_content(self, c: DynamicContent, ctx: C) -> R:
218
+ raise StaticContentVisitorTypeError(c)
File without changes
@@ -0,0 +1,195 @@
1
+ """
2
+ TODO:
3
+ - better pipeline composition lol
4
+ """
5
+ import typing as ta
6
+
7
+ from omlish import check
8
+ from omlish import dataclasses as dc
9
+ from omlish import lang
10
+ from omlish.http import all as http
11
+ from omlish.http import sse
12
+ from omlish.io.buffers import DelimitingBuffer
13
+
14
+ from ..resources import UseResources
15
+ from ..stream.services import StreamResponse
16
+ from ..stream.services import StreamResponseSink
17
+ from ..stream.services import new_stream_response
18
+ from ..types import Option
19
+ from ..types import Output
20
+
21
+
22
+ ##
23
+
24
+
25
+ @dc.dataclass()
26
+ @dc.extra_class_params(default_repr_fn=lang.opt_repr)
27
+ class HttpStreamResponseError(Exception):
28
+ response: http.BaseHttpResponse
29
+
30
+ data: bytes | None = None
31
+ data_exception: Exception | None = None
32
+
33
+ @classmethod
34
+ async def from_response(cls, response: http.AsyncStreamHttpResponse) -> 'HttpStreamResponseError':
35
+ data: bytes | None = None
36
+ data_exception: Exception | None = None
37
+
38
+ try:
39
+ data = await response.stream.readall()
40
+ except Exception as de: # noqa
41
+ data_exception = de
42
+
43
+ return HttpStreamResponseError(
44
+ response,
45
+ data=data,
46
+ data_exception=data_exception,
47
+ )
48
+
49
+
50
+ ##
51
+
52
+
53
+ class HttpStreamResponseHandler(lang.Abstract):
54
+ def start(self) -> ta.Sequence[Output]:
55
+ return ()
56
+
57
+ def finish(self) -> ta.Sequence[Output]:
58
+ return ()
59
+
60
+
61
+ ##
62
+
63
+
64
+ class BytesHttpStreamResponseHandler(HttpStreamResponseHandler, lang.Abstract):
65
+ def process_bytes(self, data: bytes) -> ta.Iterable:
66
+ return ()
67
+
68
+
69
+ class BytesHttpStreamResponseBuilder:
70
+ def __init__(
71
+ self,
72
+ http_client: http.AsyncHttpClient | None,
73
+ handling: ta.Callable[[http.AsyncStreamHttpResponse], BytesHttpStreamResponseHandler],
74
+ *,
75
+ read_chunk_size: int = -1,
76
+ ) -> None:
77
+ super().__init__()
78
+
79
+ self._http_client = http_client
80
+ self._handling = handling
81
+ self._read_chunk_size = read_chunk_size
82
+
83
+ async def new_stream_response(
84
+ self,
85
+ http_request: http.HttpRequest,
86
+ options: ta.Sequence[Option],
87
+ ) -> StreamResponse:
88
+ async with UseResources.or_new(options) as rs:
89
+ http_client = await rs.enter_async_context(http.manage_async_client(self._http_client))
90
+ http_response = await rs.enter_async_context(await http_client.stream_request(http_request))
91
+
92
+ if http_response.status != 200:
93
+ raise await HttpStreamResponseError.from_response(http_response)
94
+
95
+ handler = self._handling(http_response)
96
+
97
+ async def inner(sink: StreamResponseSink) -> ta.Sequence | None:
98
+ while True:
99
+ b = await http_response.stream.read1(self._read_chunk_size)
100
+
101
+ for v in handler.process_bytes(b):
102
+ if v is None:
103
+ break
104
+
105
+ await sink.emit(v)
106
+
107
+ if not b:
108
+ break
109
+
110
+ return handler.finish()
111
+
112
+ return await new_stream_response(
113
+ rs,
114
+ inner,
115
+ handler.start(),
116
+ )
117
+
118
+
119
+ ##
120
+
121
+
122
+ class LinesHttpStreamResponseHandler(HttpStreamResponseHandler, lang.Abstract):
123
+ def process_line(self, line: bytes) -> ta.Iterable:
124
+ return ()
125
+
126
+ def as_bytes(self) -> BytesHttpStreamResponseHandler:
127
+ return LinesBytesHttpStreamResponseHandler(self)
128
+
129
+
130
+ class LinesBytesHttpStreamResponseHandler(BytesHttpStreamResponseHandler):
131
+ def __init__(self, handler: LinesHttpStreamResponseHandler) -> None:
132
+ super().__init__()
133
+
134
+ self._handler = handler
135
+
136
+ self._db = DelimitingBuffer([b'\r', b'\n', b'\r\n'])
137
+
138
+ def start(self) -> ta.Sequence[Output]:
139
+ return self._handler.start()
140
+
141
+ def process_bytes(self, data: bytes) -> ta.Iterable:
142
+ for o in self._db.feed(data):
143
+ if isinstance(o, bytes):
144
+ yield from self._handler.process_line(o)
145
+
146
+ else:
147
+ raise TypeError(o)
148
+
149
+ def finish(self) -> ta.Sequence[Output]:
150
+ check.state(self._db.is_closed)
151
+
152
+ return self._handler.finish()
153
+
154
+
155
+ ##
156
+
157
+
158
+ class SseHttpStreamResponseHandler(HttpStreamResponseHandler, lang.Abstract):
159
+ def process_sse(self, so: sse.SseDecoderOutput) -> ta.Iterable:
160
+ return ()
161
+
162
+ def as_lines(self) -> LinesHttpStreamResponseHandler:
163
+ return SseLinesHttpStreamResponseHandler(self)
164
+
165
+
166
+ class SseLinesHttpStreamResponseHandler(LinesHttpStreamResponseHandler):
167
+ def __init__(self, handler: SseHttpStreamResponseHandler) -> None:
168
+ super().__init__()
169
+
170
+ self._handler = handler
171
+
172
+ self._sd = sse.SseDecoder()
173
+
174
+ def start(self) -> ta.Sequence[Output]:
175
+ return self._handler.start()
176
+
177
+ def process_line(self, line: bytes) -> ta.Iterable:
178
+ for so in self._sd.process_line(line):
179
+ yield from self._handler.process_sse(so)
180
+
181
+ def finish(self) -> ta.Sequence[Output]:
182
+ return self._handler.finish()
183
+
184
+
185
+ #
186
+
187
+
188
+ class SimpleSseLinesHttpStreamResponseHandler(SseHttpStreamResponseHandler):
189
+ def __init__(self, fn: ta.Callable[[sse.SseDecoderOutput], ta.Iterable]) -> None:
190
+ super().__init__()
191
+
192
+ self._fn = fn
193
+
194
+ def process_sse(self, so: sse.SseDecoderOutput) -> ta.Iterable:
195
+ return self._fn(so)
@@ -27,7 +27,7 @@ MAX_LINE_LENGTH = 2_000
27
27
 
28
28
  @tool_spec_override(
29
29
  desc=f"""
30
- Reads a file from the local filesystem. You can access any file directly by using this tool.
30
+ Reads a file from the local filesystem. You can access any file directly by using this tool.
31
31
 
32
32
  Assume this tool is able to read all files on the machine. If the User provides a path to a file assume that
33
33
  path is valid. It is okay to read a file that does not exist; an error will be returned.
@@ -5,10 +5,10 @@ TODO:
5
5
  - any directory with unlisted children will be suffixed inline with '...'
6
6
  - absence of '...' indicates an empty directory
7
7
  """
8
- import dataclasses as dc
9
8
  import typing as ta
10
9
 
11
10
  from omlish import check
11
+ from omlish import dataclasses as dc
12
12
  from omlish import lang
13
13
 
14
14
  from .running import DirLsItem
@@ -1,8 +1,8 @@
1
- import dataclasses as dc
2
1
  import os.path
3
2
  import typing as ta
4
3
 
5
4
  from omlish import check
5
+ from omlish import dataclasses as dc
6
6
  from omlish import lang
7
7
 
8
8
 
@@ -8,6 +8,7 @@ from omlish import lang
8
8
  from omlish import marshal as msh
9
9
 
10
10
  from ....content.namespaces import ContentNamespace
11
+ from ....content.namespaces import NamespaceContent
11
12
  from ....tools.execution.catalog import ToolCatalogEntry
12
13
  from ....tools.execution.reflect import reflect_tool_catalog_entry
13
14
  from ....tools.reflect import tool_spec_override
@@ -311,7 +312,7 @@ class TodoWriteDescriptionChunks(ContentNamespace):
311
312
 
312
313
 
313
314
  @tool_spec_override(
314
- desc=TodoWriteDescriptionChunks,
315
+ desc=NamespaceContent(TodoWriteDescriptionChunks),
315
316
  )
316
317
  def execute_todo_write_tool(todo_items: ta.Sequence[TodoItem]) -> ta.Sequence[TodoItem]:
317
318
  if todo_items:
@@ -3,9 +3,9 @@ TODO:
3
3
  - enums lol
4
4
  - * with ToolParam-like desc metadata somehow *
5
5
  """
6
- import dataclasses as dc
7
6
  import typing as ta
8
7
 
8
+ from omlish import dataclasses as dc
9
9
  from omlish import lang
10
10
 
11
11
  from ...tools.reflect import tool_param_metadata
@@ -31,6 +31,10 @@ class MaxTokens(LlmOption, tv.UniqueScalarTypedValue[int]):
31
31
  pass
32
32
 
33
33
 
34
+ class MaxCompletionTokens(LlmOption, tv.UniqueScalarTypedValue[int]):
35
+ pass
36
+
37
+
34
38
  ##
35
39
 
36
40
 
@@ -3,9 +3,13 @@ import datetime
3
3
  import typing as ta
4
4
  import uuid
5
5
 
6
+ from omlish import check
7
+ from omlish import dataclasses as dc
6
8
  from omlish import lang
7
9
  from omlish import typedvalues as tv
8
10
 
11
+ from ._typedvalues import _tv_field_metadata
12
+
9
13
 
10
14
  ##
11
15
 
@@ -21,9 +25,9 @@ MetadataT = ta.TypeVar('MetadataT', bound=Metadata)
21
25
 
22
26
 
23
27
  class MetadataContainer(
24
- tv.TypedValueGeneric[MetadataT],
25
28
  lang.Abstract,
26
29
  lang.PackageSealed,
30
+ ta.Generic[MetadataT],
27
31
  ):
28
32
  @property
29
33
  @abc.abstractmethod
@@ -31,13 +35,63 @@ class MetadataContainer(
31
35
  raise NotImplementedError
32
36
 
33
37
  @abc.abstractmethod
34
- def with_metadata(self, *mds: MetadataT, override: bool = False) -> ta.Self:
38
+ def with_metadata(
39
+ self,
40
+ *add: MetadataT,
41
+ discard: ta.Iterable[type] | None = None,
42
+ override: bool = False,
43
+ ) -> ta.Self:
35
44
  raise NotImplementedError
36
45
 
37
46
 
38
47
  ##
39
48
 
40
49
 
50
+ @dc.dataclass(frozen=True)
51
+ class MetadataContainerDataclass( # noqa
52
+ MetadataContainer[MetadataT],
53
+ lang.Abstract,
54
+ ):
55
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
56
+ super().__init_subclass__(**kwargs)
57
+
58
+ check.state(hasattr(cls, '_metadata'))
59
+
60
+ @staticmethod
61
+ def _configure_metadata_field(md_fld, md_cls):
62
+ dc.set_field_metadata(
63
+ check.isinstance(md_fld, dc.Field),
64
+ _tv_field_metadata(
65
+ check.not_none(md_cls),
66
+ marshal_name='metadata',
67
+ ),
68
+ )
69
+
70
+ @property
71
+ def metadata(self) -> tv.TypedValues[MetadataT]:
72
+ return check.isinstance(getattr(self, '_metadata'), tv.TypedValues)
73
+
74
+ def with_metadata(
75
+ self,
76
+ *add: MetadataT,
77
+ discard: ta.Iterable[type] | None = None,
78
+ override: bool = False,
79
+ ) -> ta.Self:
80
+ new = (old := self.metadata).update(
81
+ *add,
82
+ discard=discard,
83
+ override=override,
84
+ )
85
+
86
+ if new is old:
87
+ return self
88
+
89
+ return dc.replace(self, _metadata=new) # type: ignore[call-arg] # noqa
90
+
91
+
92
+ ##
93
+
94
+
41
95
  class CommonMetadata(Metadata, lang.Abstract):
42
96
  pass
43
97