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
@@ -8,30 +8,24 @@ from omlish import marshal as msh
8
8
  from omlish import typedvalues as tv
9
9
  from omlish.formats import json
10
10
  from omlish.http import all as http
11
- from omlish.io.buffers import DelimitingBuffer
11
+ from omlish.http import sse
12
12
 
13
13
  from .....backends.google.protocol import types as pt
14
- from ....chat.choices.types import ChatChoicesOutputs
15
- from ....chat.messages import AiMessage
16
- from ....chat.messages import Message
17
- from ....chat.messages import SystemMessage
18
- from ....chat.messages import ToolUseMessage
19
- from ....chat.messages import ToolUseResultMessage
20
- from ....chat.messages import UserMessage
21
- from ....chat.stream.services import ChatChoicesStreamRequest
22
- from ....chat.stream.services import ChatChoicesStreamResponse
23
- from ....chat.stream.services import static_check_is_chat_choices_stream_service
24
- from ....chat.stream.types import AiChoiceDeltas
25
- from ....chat.stream.types import AiChoicesDeltas
26
- from ....chat.stream.types import ContentAiChoiceDelta
27
- from ....chat.stream.types import ToolUseAiChoiceDelta
14
+ from ....chat.choices.stream.services import ChatChoicesStreamRequest
15
+ from ....chat.choices.stream.services import ChatChoicesStreamResponse
16
+ from ....chat.choices.stream.services import static_check_is_chat_choices_stream_service
17
+ from ....chat.choices.stream.types import AiChoiceDeltas
18
+ from ....chat.choices.stream.types import AiChoicesDeltas
19
+ from ....chat.stream.types import ContentAiDelta
20
+ from ....chat.stream.types import ToolUseAiDelta
28
21
  from ....chat.tools.types import Tool
22
+ from ....http.stream import BytesHttpStreamResponseBuilder
23
+ from ....http.stream import SimpleSseLinesHttpStreamResponseHandler
29
24
  from ....models.configs import ModelName
30
- from ....resources import UseResources
31
25
  from ....standard import ApiKey
32
- from ....stream.services import StreamResponseSink
33
- from ....stream.services import new_stream_response
34
26
  from .names import MODEL_NAMES
27
+ from .protocol import make_msg_content
28
+ from .protocol import pop_system_instructions
35
29
  from .tools import build_tool_spec_schema
36
30
 
37
31
 
@@ -46,80 +40,53 @@ from .tools import build_tool_spec_schema
46
40
  class GoogleChatChoicesStreamService:
47
41
  DEFAULT_MODEL_NAME: ta.ClassVar[ModelName] = ModelName(check.not_none(MODEL_NAMES.default))
48
42
 
49
- def __init__(self, *configs: ApiKey | ModelName) -> None:
43
+ def __init__(
44
+ self,
45
+ *configs: ApiKey | ModelName,
46
+ http_client: http.AsyncHttpClient | None = None,
47
+ ) -> None:
50
48
  super().__init__()
51
49
 
50
+ self._http_client = http_client
51
+
52
52
  with tv.consume(*configs) as cc:
53
53
  self._model_name = cc.pop(self.DEFAULT_MODEL_NAME)
54
54
  self._api_key = ApiKey.pop_secret(cc, env='GEMINI_API_KEY')
55
55
 
56
- def _make_str_content(
57
- self,
58
- s: str | None,
59
- *,
60
- role: pt.ContentRole | None = None,
61
- ) -> pt.Content | None:
62
- if s is None:
63
- return None
64
-
65
- return pt.Content(
66
- parts=[pt.Part(
67
- text=check.not_none(s),
68
- )],
69
- role=role,
70
- )
71
-
72
- def _make_msg_content(self, m: Message) -> pt.Content:
73
- if isinstance(m, (AiMessage, SystemMessage, UserMessage)):
74
- return check.not_none(self._make_str_content(
75
- check.isinstance(m.c, str),
76
- role=self.ROLES_MAP[type(m)],
77
- ))
78
-
79
- elif isinstance(m, ToolUseResultMessage):
80
- tr_resp_val: pt.Value
81
- if m.tur.c is None:
82
- tr_resp_val = pt.NullValue() # type: ignore[unreachable]
83
- elif isinstance(m.tur.c, str):
84
- tr_resp_val = pt.StringValue(m.tur.c)
85
- else:
86
- raise TypeError(m.tur.c)
87
- return pt.Content(
88
- parts=[pt.Part(
89
- function_response=pt.FunctionResponse(
90
- id=m.tur.id,
91
- name=m.tur.name,
92
- response={
93
- 'value': tr_resp_val,
94
- },
95
- ),
96
- )],
97
- )
98
-
99
- elif isinstance(m, ToolUseMessage):
100
- return pt.Content(
101
- parts=[pt.Part(
102
- function_call=pt.FunctionCall(
103
- id=m.tu.id,
104
- name=m.tu.name,
105
- args=m.tu.args,
106
- ),
107
- )],
108
- role='model',
109
- )
110
-
111
- else:
112
- raise TypeError(m)
113
-
114
56
  BASE_URL: ta.ClassVar[str] = 'https://generativelanguage.googleapis.com/v1beta/models'
115
57
 
116
- ROLES_MAP: ta.ClassVar[ta.Mapping[type[Message], pt.ContentRole | None]] = { # noqa
117
- SystemMessage: None,
118
- UserMessage: 'user',
119
- AiMessage: 'model',
120
- }
58
+ def _process_sse(self, so: sse.SseDecoderOutput) -> ta.Iterable[AiChoicesDeltas | None]:
59
+ if not (isinstance(so, sse.SseEvent) and so.type == b'message'):
60
+ return
61
+
62
+ gcr = msh.unmarshal(json.loads(so.data.decode('utf-8')), pt.GenerateContentResponse) # noqa
63
+ cnd = check.single(check.not_none(gcr.candidates))
64
+
65
+ for p in check.not_none(cnd.content).parts or []:
66
+ if (txt := p.text) is not None:
67
+ check.none(p.function_call)
68
+ yield AiChoicesDeltas([
69
+ AiChoiceDeltas([
70
+ ContentAiDelta(check.not_none(txt)),
71
+ ]),
72
+ ])
73
+
74
+ elif (fc := p.function_call) is not None:
75
+ check.none(p.text)
76
+ yield AiChoicesDeltas([
77
+ AiChoiceDeltas([
78
+ ToolUseAiDelta(
79
+ id=fc.id,
80
+ name=fc.name,
81
+ args=fc.args,
82
+ ),
83
+ ]),
84
+ ])
85
+
86
+ else:
87
+ raise ValueError(p)
121
88
 
122
- READ_CHUNK_SIZE = 64 * 1024
89
+ READ_CHUNK_SIZE: ta.ClassVar[int] = -1
123
90
 
124
91
  async def invoke(
125
92
  self,
@@ -127,13 +94,6 @@ class GoogleChatChoicesStreamService:
127
94
  ) -> ChatChoicesStreamResponse:
128
95
  key = check.not_none(self._api_key).reveal()
129
96
 
130
- msgs = list(request.v)
131
-
132
- system_inst: pt.Content | None = None
133
- if msgs and isinstance(m0 := msgs[0], SystemMessage):
134
- system_inst = self._make_msg_content(m0)
135
- msgs.pop(0)
136
-
137
97
  g_tools: list[pt.Tool] = []
138
98
  with tv.TypedValues(*request.options).consume() as oc:
139
99
  t: Tool
@@ -142,11 +102,15 @@ class GoogleChatChoicesStreamService:
142
102
  function_declarations=[build_tool_spec_schema(t.spec)],
143
103
  ))
144
104
 
105
+ msgs = list(request.v)
106
+
107
+ system_inst = pop_system_instructions(msgs)
108
+
145
109
  g_req = pt.GenerateContentRequest(
146
110
  contents=[
147
- self._make_msg_content(m)
111
+ make_msg_content(m)
148
112
  for m in msgs
149
- ],
113
+ ] or None,
150
114
  tools=g_tools or None,
151
115
  system_instruction=system_inst,
152
116
  )
@@ -162,53 +126,11 @@ class GoogleChatChoicesStreamService:
162
126
  method='POST',
163
127
  )
164
128
 
165
- async with UseResources.or_new(request.options) as rs:
166
- http_client = rs.enter_context(http.client())
167
- http_response = rs.enter_context(http_client.stream_request(http_request))
168
-
169
- async def inner(sink: StreamResponseSink[AiChoicesDeltas]) -> ta.Sequence[ChatChoicesOutputs] | None:
170
- db = DelimitingBuffer([b'\r', b'\n', b'\r\n'])
171
- while True:
172
- # FIXME: read1 not on response stream protocol
173
- b = http_response.stream.read1(self.READ_CHUNK_SIZE) # type: ignore[attr-defined]
174
- for bl in db.feed(b):
175
- if isinstance(bl, DelimitingBuffer.Incomplete):
176
- # FIXME: handle
177
- return []
178
-
179
- l = bl.decode('utf-8')
180
- if not l:
181
- continue
182
-
183
- if l.startswith('data: '):
184
- gcr = msh.unmarshal(json.loads(l[6:]), pt.GenerateContentResponse) # noqa
185
- cnd = check.single(check.not_none(gcr.candidates))
186
-
187
- for p in check.not_none(cnd.content).parts or []:
188
- if (txt := p.text) is not None:
189
- check.none(p.function_call)
190
- await sink.emit(AiChoicesDeltas([
191
- AiChoiceDeltas([
192
- ContentAiChoiceDelta(check.not_none(txt)),
193
- ]),
194
- ]))
195
-
196
- elif (fc := p.function_call) is not None:
197
- check.none(p.text)
198
- await sink.emit(AiChoicesDeltas([
199
- AiChoiceDeltas([
200
- ToolUseAiChoiceDelta(
201
- id=fc.id,
202
- name=fc.name,
203
- args=fc.args,
204
- ),
205
- ]),
206
- ]))
207
-
208
- else:
209
- raise ValueError(p)
210
-
211
- if not b:
212
- return []
213
-
214
- return await new_stream_response(rs, inner)
129
+ return await BytesHttpStreamResponseBuilder(
130
+ self._http_client,
131
+ lambda http_response: SimpleSseLinesHttpStreamResponseHandler(self._process_sse).as_lines().as_bytes(),
132
+ read_chunk_size=self.READ_CHUNK_SIZE,
133
+ ).new_stream_response(
134
+ http_request,
135
+ request.options,
136
+ )
@@ -7,8 +7,8 @@ from omlish import check
7
7
  from omlish import dataclasses as dc
8
8
 
9
9
  from .....backends.google.protocol import types as pt
10
- from ....content.prepare import ContentStrPreparer
11
- from ....content.prepare import default_content_str_preparer
10
+ from ....content.transform.prepare import ContentStrPreparer
11
+ from ....content.transform.prepare import default_content_str_preparer
12
12
  from ....tools.types import EnumToolDtype
13
13
  from ....tools.types import MappingToolDtype
14
14
  from ....tools.types import NullableToolDtype
File without changes
@@ -0,0 +1,77 @@
1
+ import typing as ta
2
+
3
+ from omlish import check
4
+ from omlish import marshal as msh
5
+ from omlish import typedvalues as tv
6
+ from omlish.formats import json
7
+ from omlish.http import all as http
8
+
9
+ from .....backends.groq import protocol as pt
10
+ from .....backends.groq.clients import REQUIRED_HTTP_HEADERS
11
+ from ....chat.choices.services import ChatChoicesRequest
12
+ from ....chat.choices.services import ChatChoicesResponse
13
+ from ....chat.choices.services import static_check_is_chat_choices_service
14
+ from ....chat.tools.types import Tool
15
+ from ....models.configs import ModelName
16
+ from ....standard import ApiKey
17
+ from ....standard import DefaultOptions
18
+ from .names import MODEL_NAMES
19
+ from .protocol import build_gq_request_messages
20
+ from .protocol import build_gq_request_tool
21
+ from .protocol import build_mc_choices_response
22
+
23
+
24
+ ##
25
+
26
+
27
+ # @omlish-manifest $.minichain.registries.manifests.RegistryManifest(
28
+ # name='groq',
29
+ # type='ChatChoicesService',
30
+ # )
31
+ @static_check_is_chat_choices_service
32
+ class GroqChatChoicesService:
33
+ DEFAULT_MODEL_NAME: ta.ClassVar[ModelName] = ModelName(check.not_none(MODEL_NAMES.default))
34
+
35
+ def __init__(
36
+ self,
37
+ *configs: ApiKey | ModelName | DefaultOptions,
38
+ http_client: http.AsyncHttpClient | None = None,
39
+ ) -> None:
40
+ super().__init__()
41
+
42
+ self._http_client = http_client
43
+
44
+ with tv.consume(*configs) as cc:
45
+ self._model_name = cc.pop(self.DEFAULT_MODEL_NAME)
46
+ self._api_key = ApiKey.pop_secret(cc, env='GROQ_API_KEY')
47
+ self._default_options: tv.TypedValues = DefaultOptions.pop(cc)
48
+
49
+ async def invoke(self, request: ChatChoicesRequest) -> ChatChoicesResponse:
50
+ tools: list[pt.ChatCompletionRequest.Tool] = []
51
+ with tv.TypedValues(*request.options).consume() as oc:
52
+ t: Tool
53
+ for t in oc.pop(Tool, []):
54
+ tools.append(build_gq_request_tool(t))
55
+
56
+ gq_request = pt.ChatCompletionRequest(
57
+ messages=build_gq_request_messages(request.v),
58
+ model=MODEL_NAMES.resolve(self._model_name.v),
59
+ tools=tools or None,
60
+ )
61
+
62
+ raw_request = msh.marshal(gq_request)
63
+
64
+ http_response = await http.async_request(
65
+ 'https://api.groq.com/openai/v1/chat/completions',
66
+ headers={
67
+ http.consts.HEADER_CONTENT_TYPE: http.consts.CONTENT_TYPE_JSON,
68
+ http.consts.HEADER_AUTH: http.consts.format_bearer_auth_header(check.not_none(self._api_key).reveal()),
69
+ **REQUIRED_HTTP_HEADERS,
70
+ },
71
+ data=json.dumps(raw_request).encode('utf-8'),
72
+ client=self._http_client,
73
+ )
74
+
75
+ raw_response = json.loads(check.not_none(http_response.data).decode('utf-8'))
76
+
77
+ return build_mc_choices_response(msh.unmarshal(raw_response, pt.ChatCompletionResponse))
@@ -0,0 +1,48 @@
1
+ """
2
+ https://console.groq.com/docs/models
3
+
4
+ curl -X GET "https://api.groq.com/openai/v1/models" \
5
+ -H "Authorization: Bearer $GROQ_API_KEY" \
6
+ -H "Content-Type: application/json"
7
+
8
+ "compound-beta",
9
+ "compound-beta-mini",
10
+ "gemma2-9b-it",
11
+ "llama-3.1-8b-instant",
12
+ "llama-3.3-70b-versatile",
13
+ "meta-llama/llama-4-maverick-17b-128e-instruct",
14
+ "meta-llama/llama-4-scout-17b-16e-instruct",
15
+ "meta-llama/llama-guard-4-12b",
16
+ "moonshotai/kimi-k2-instruct",
17
+ "openai/gpt-oss-120b",
18
+ "openai/gpt-oss-20b",
19
+ "qwen/qwen3-32b",
20
+ """
21
+ from ....models.names import ModelNameCollection
22
+ from ...strings.manifests import BackendStringsManifest
23
+
24
+
25
+ ##
26
+
27
+
28
+ MODEL_NAMES = ModelNameCollection(
29
+ default='gpt-oss-120b',
30
+ aliases={
31
+ 'gpt-oss-120b': 'openai/gpt-oss-120b',
32
+ 'openai/gpt-oss-120b': None,
33
+
34
+ 'gpt-oss-20b': 'openai/gpt-oss-20b',
35
+ 'openai/gpt-oss-20b': None,
36
+ },
37
+ )
38
+
39
+
40
+ # @omlish-manifest
41
+ _BACKEND_STRINGS_MANIFEST = BackendStringsManifest(
42
+ [
43
+ 'ChatChoicesService',
44
+ 'ChatChoicesStreamService',
45
+ ],
46
+ 'groq',
47
+ model_names=MODEL_NAMES,
48
+ )
@@ -0,0 +1,143 @@
1
+ import itertools
2
+
3
+ from omlish import check
4
+ from omlish.formats import json
5
+
6
+ from .....backends.groq import protocol as pt
7
+ from ....chat.choices.services import ChatChoicesResponse
8
+ from ....chat.choices.stream.types import AiChoiceDeltas
9
+ from ....chat.choices.types import AiChoice
10
+ from ....chat.messages import AiMessage
11
+ from ....chat.messages import AnyAiMessage
12
+ from ....chat.messages import Chat
13
+ from ....chat.messages import SystemMessage
14
+ from ....chat.messages import ToolUseMessage
15
+ from ....chat.messages import ToolUseResultMessage
16
+ from ....chat.messages import UserMessage
17
+ from ....chat.stream.types import AiDelta
18
+ from ....chat.stream.types import ContentAiDelta
19
+ from ....chat.stream.types import ToolUseAiDelta
20
+ from ....chat.tools.types import Tool
21
+ from ....content.transform.prepare import prepare_content_str
22
+ from ....tools.jsonschema import build_tool_spec_params_json_schema
23
+ from ....tools.types import ToolUse
24
+
25
+
26
+ ##
27
+
28
+
29
+ def build_gq_request_messages(chat: Chat) -> list[pt.ChatCompletionRequest.Message]:
30
+ gq_msgs: list[pt.ChatCompletionRequest.Message] = []
31
+
32
+ for _, g in itertools.groupby(chat, lambda mc_m: isinstance(mc_m, AnyAiMessage)):
33
+ mc_msgs = list(g)
34
+
35
+ if isinstance(mc_msgs[0], AnyAiMessage):
36
+ tups: list[tuple[AiMessage | None, list[ToolUseMessage]]] = []
37
+ for mc_msg in mc_msgs:
38
+ if isinstance(mc_msg, AiMessage):
39
+ tups.append((mc_msg, []))
40
+
41
+ elif isinstance(mc_msg, ToolUseMessage):
42
+ if not tups:
43
+ tups.append((None, []))
44
+ tups[-1][1].append(mc_msg)
45
+
46
+ else:
47
+ raise TypeError(mc_msg)
48
+
49
+ for mc_ai_msg, mc_tu_msgs in tups:
50
+ gq_msgs.append(pt.ChatCompletionRequest.AssistantMessage(
51
+ content=check.isinstance(mc_ai_msg.c, str) if mc_ai_msg is not None else None,
52
+ tool_calls=[
53
+ pt.ChatCompletionRequest.AssistantMessage.ToolCall(
54
+ function=pt.ChatCompletionRequest.AssistantMessage.ToolCall.Function(
55
+ name=mc_tu_msg.tu.name,
56
+ arguments=check.not_none(mc_tu_msg.tu.raw_args),
57
+ ),
58
+ id=check.not_none(mc_tu_msg.tu.id),
59
+ )
60
+ for mc_tu_msg in mc_tu_msgs
61
+ ] if mc_tu_msgs else None,
62
+ ))
63
+
64
+ else:
65
+ for mc_msg in mc_msgs:
66
+ if isinstance(mc_msg, SystemMessage):
67
+ gq_msgs.append(pt.ChatCompletionRequest.SystemMessage(
68
+ content=check.isinstance(mc_msg.c, str),
69
+ ))
70
+
71
+ elif isinstance(mc_msg, UserMessage):
72
+ gq_msgs.append(pt.ChatCompletionRequest.UserMessage(
73
+ content=check.isinstance(mc_msg.c, str),
74
+ ))
75
+
76
+ elif isinstance(mc_msg, ToolUseResultMessage):
77
+ gq_msgs.append(pt.ChatCompletionRequest.ToolMessage(
78
+ tool_call_id=check.not_none(mc_msg.tur.id),
79
+ content=check.isinstance(mc_msg.tur.c, str),
80
+ ))
81
+
82
+ else:
83
+ raise TypeError(mc_msg)
84
+
85
+ return gq_msgs
86
+
87
+
88
+ def build_gq_request_tool(t: Tool) -> pt.ChatCompletionRequest.Tool:
89
+ return pt.ChatCompletionRequest.Tool(
90
+ function=pt.ChatCompletionRequest.Tool.Function(
91
+ name=check.not_none(t.spec.name),
92
+ description=prepare_content_str(t.spec.desc) if t.spec.desc is not None else None,
93
+ parameters=build_tool_spec_params_json_schema(t.spec),
94
+ ),
95
+ )
96
+
97
+
98
+ def build_mc_choices_response(gq_resp: pt.ChatCompletionResponse) -> ChatChoicesResponse:
99
+ def build_choice(gq_choice: pt.ChatCompletionResponse.Choice) -> AiChoice:
100
+ gq_msg = gq_choice.message
101
+
102
+ lst: list[AnyAiMessage] = []
103
+
104
+ if gq_msg.content is not None:
105
+ lst.append(AiMessage(
106
+ check.isinstance(gq_msg.content, str),
107
+ ))
108
+
109
+ for gq_tc in gq_msg.tool_calls or []:
110
+ lst.append(ToolUseMessage(ToolUse(
111
+ id=gq_tc.id,
112
+ name=gq_tc.function.name,
113
+ args=json.loads(gq_tc.function.arguments or '{}'),
114
+ raw_args=gq_tc.function.arguments,
115
+ )))
116
+
117
+ return AiChoice(lst)
118
+
119
+ return ChatChoicesResponse(list(map(build_choice, gq_resp.choices)))
120
+
121
+
122
+ def build_mc_ai_choice_deltas(delta: pt.ChatCompletionChunk.Choice.Delta) -> AiChoiceDeltas:
123
+ if delta.role in (None, 'assistant'):
124
+ lst: list[AiDelta] = []
125
+
126
+ if delta.content is not None:
127
+ lst.append(ContentAiDelta(delta.content))
128
+
129
+ for tc in delta.tool_calls or []:
130
+ tc_fn = check.not_none(tc.function)
131
+ lst.append(ToolUseAiDelta(
132
+ id=tc.id,
133
+ name=check.not_none(tc_fn.name),
134
+ args=json.loads(tc_fn.arguments or '{}'),
135
+ ))
136
+
137
+ return AiChoiceDeltas(lst)
138
+
139
+ elif delta.channel in ('analysis', 'commentary'):
140
+ return AiChoiceDeltas([])
141
+
142
+ else:
143
+ raise ValueError(delta)
@@ -0,0 +1,114 @@
1
+ import typing as ta
2
+
3
+ from omlish import check
4
+ from omlish import marshal as msh
5
+ from omlish import typedvalues as tv
6
+ from omlish.formats import json
7
+ from omlish.http import all as http
8
+ from omlish.http import sse
9
+
10
+ from .....backends.groq import protocol as pt
11
+ from .....backends.groq.clients import REQUIRED_HTTP_HEADERS
12
+ from ....chat.choices.stream.services import ChatChoicesStreamRequest
13
+ from ....chat.choices.stream.services import ChatChoicesStreamResponse
14
+ from ....chat.choices.stream.services import static_check_is_chat_choices_stream_service
15
+ from ....chat.choices.stream.types import AiChoicesDeltas
16
+ from ....chat.tools.types import Tool
17
+ from ....configs import Config
18
+ from ....http.stream import BytesHttpStreamResponseBuilder
19
+ from ....http.stream import SimpleSseLinesHttpStreamResponseHandler
20
+ from ....standard import ApiKey
21
+ from .chat import GroqChatChoicesService
22
+ from .names import MODEL_NAMES
23
+ from .protocol import build_gq_request_messages
24
+ from .protocol import build_gq_request_tool
25
+ from .protocol import build_mc_ai_choice_deltas
26
+
27
+
28
+ ##
29
+
30
+
31
+ # @omlish-manifest $.minichain.registries.manifests.RegistryManifest(
32
+ # name='groq',
33
+ # type='ChatChoicesStreamService',
34
+ # )
35
+ @static_check_is_chat_choices_stream_service
36
+ class GroqChatChoicesStreamService:
37
+ def __init__(
38
+ self,
39
+ *configs: Config,
40
+ http_client: http.AsyncHttpClient | None = None,
41
+ ) -> None:
42
+ super().__init__()
43
+
44
+ self._http_client = http_client
45
+
46
+ with tv.consume(*configs) as cc:
47
+ self._model_name = cc.pop(GroqChatChoicesService.DEFAULT_MODEL_NAME)
48
+ self._api_key = ApiKey.pop_secret(cc, env='GROQ_API_KEY')
49
+
50
+ URL: ta.ClassVar[str] = 'https://api.groq.com/openai/v1/chat/completions'
51
+
52
+ def _process_sse(self, so: sse.SseDecoderOutput) -> ta.Sequence[AiChoicesDeltas | None]:
53
+ if not (isinstance(so, sse.SseEvent) and so.type == b'message'):
54
+ return []
55
+
56
+ ss = so.data.decode('utf-8')
57
+ if ss == '[DONE]':
58
+ return [None]
59
+
60
+ sj = json.loads(ss) # ChatCompletionChunk
61
+
62
+ check.state(sj['object'] == 'chat.completion.chunk')
63
+
64
+ ccc = msh.unmarshal(sj, pt.ChatCompletionChunk)
65
+
66
+ # FIXME: stop reason
67
+ if not ccc.choices:
68
+ return []
69
+
70
+ if any(choice.finish_reason for choice in ccc.choices):
71
+ check.state(all(choice.finish_reason for choice in ccc.choices))
72
+ return [None]
73
+
74
+ return [AiChoicesDeltas([
75
+ build_mc_ai_choice_deltas(choice.delta)
76
+ for choice in ccc.choices
77
+ ])]
78
+
79
+ READ_CHUNK_SIZE: ta.ClassVar[int] = -1
80
+
81
+ async def invoke(self, request: ChatChoicesStreamRequest) -> ChatChoicesStreamResponse:
82
+ tools: list[pt.ChatCompletionRequest.Tool] = []
83
+ with tv.TypedValues(*request.options).consume() as oc:
84
+ t: Tool
85
+ for t in oc.pop(Tool, []):
86
+ tools.append(build_gq_request_tool(t))
87
+
88
+ gq_request = pt.ChatCompletionRequest(
89
+ messages=build_gq_request_messages(request.v),
90
+ model=MODEL_NAMES.resolve(self._model_name.v),
91
+ tools=tools or None,
92
+ stream=True,
93
+ )
94
+
95
+ raw_request = msh.marshal(gq_request)
96
+
97
+ http_request = http.HttpRequest(
98
+ self.URL,
99
+ headers={
100
+ http.consts.HEADER_CONTENT_TYPE: http.consts.CONTENT_TYPE_JSON,
101
+ http.consts.HEADER_AUTH: http.consts.format_bearer_auth_header(check.not_none(self._api_key).reveal()),
102
+ **REQUIRED_HTTP_HEADERS,
103
+ },
104
+ data=json.dumps(raw_request).encode('utf-8'),
105
+ )
106
+
107
+ return await BytesHttpStreamResponseBuilder(
108
+ self._http_client,
109
+ lambda http_response: SimpleSseLinesHttpStreamResponseHandler(self._process_sse).as_lines().as_bytes(),
110
+ read_chunk_size=self.READ_CHUNK_SIZE,
111
+ ).new_stream_response(
112
+ http_request,
113
+ request.options,
114
+ )
@@ -3,8 +3,6 @@ TODO:
3
3
  - local-only check first
4
4
  - cat ~/.cache/.../models/.../refs/main -> c5bfd839cd4cda0e5a39a97e00218d9c56e468af
5
5
  """
6
- import typing as ta
7
-
8
6
  from omlish import lang
9
7
 
10
8
  from ....models.configs import ModelRepo
@@ -12,10 +10,8 @@ from ....models.repos.resolving import ModelRepoResolver
12
10
  from ....models.repos.resolving import ResolvedModelRepo
13
11
 
14
12
 
15
- if ta.TYPE_CHECKING:
13
+ with lang.auto_proxy_import(globals()):
16
14
  import huggingface_hub as hf
17
- else:
18
- hf = lang.proxy_import('huggingface_hub')
19
15
 
20
16
 
21
17
  ##