ommlds 0.0.0.dev480__py3-none-any.whl → 0.0.0.dev503__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. ommlds/.omlish-manifests.json +100 -33
  2. ommlds/README.md +11 -0
  3. ommlds/__about__.py +9 -6
  4. ommlds/backends/anthropic/protocol/__init__.py +13 -1
  5. ommlds/backends/anthropic/protocol/_dataclasses.py +1625 -0
  6. ommlds/backends/anthropic/protocol/sse/events.py +2 -0
  7. ommlds/backends/cerebras/__init__.py +7 -0
  8. ommlds/backends/cerebras/_dataclasses.py +4254 -0
  9. ommlds/backends/cerebras/_marshal.py +24 -0
  10. ommlds/backends/cerebras/protocol.py +312 -0
  11. ommlds/backends/google/protocol/__init__.py +13 -0
  12. ommlds/backends/google/protocol/_dataclasses.py +5997 -0
  13. ommlds/backends/groq/__init__.py +7 -0
  14. ommlds/backends/groq/_dataclasses.py +3901 -0
  15. ommlds/backends/groq/clients.py +9 -0
  16. ommlds/backends/llamacpp/logging.py +4 -1
  17. ommlds/backends/mlx/caching.py +7 -3
  18. ommlds/backends/mlx/cli.py +10 -7
  19. ommlds/backends/mlx/generation.py +18 -16
  20. ommlds/backends/mlx/limits.py +10 -6
  21. ommlds/backends/mlx/loading.py +7 -4
  22. ommlds/backends/ollama/__init__.py +7 -0
  23. ommlds/backends/ollama/_dataclasses.py +3488 -0
  24. ommlds/backends/ollama/protocol.py +3 -0
  25. ommlds/backends/openai/protocol/__init__.py +15 -1
  26. ommlds/backends/openai/protocol/_dataclasses.py +7708 -0
  27. ommlds/backends/tavily/__init__.py +7 -0
  28. ommlds/backends/tavily/_dataclasses.py +1734 -0
  29. ommlds/backends/transformers/__init__.py +14 -0
  30. ommlds/cli/__init__.py +7 -0
  31. ommlds/cli/_dataclasses.py +3515 -0
  32. ommlds/cli/backends/catalog.py +0 -5
  33. ommlds/cli/backends/inject.py +70 -7
  34. ommlds/cli/backends/meta.py +82 -0
  35. ommlds/cli/content/messages.py +1 -1
  36. ommlds/cli/inject.py +11 -3
  37. ommlds/cli/main.py +137 -68
  38. ommlds/cli/rendering/types.py +6 -0
  39. ommlds/cli/secrets.py +2 -1
  40. ommlds/cli/sessions/base.py +1 -10
  41. ommlds/cli/sessions/chat/configs.py +9 -17
  42. ommlds/cli/sessions/chat/{chat → drivers}/ai/configs.py +3 -1
  43. ommlds/cli/sessions/chat/drivers/ai/events.py +57 -0
  44. ommlds/cli/sessions/chat/{chat → drivers}/ai/inject.py +10 -3
  45. ommlds/cli/sessions/chat/{chat → drivers}/ai/rendering.py +1 -1
  46. ommlds/cli/sessions/chat/{chat → drivers}/ai/services.py +1 -1
  47. ommlds/cli/sessions/chat/{chat → drivers}/ai/tools.py +4 -8
  48. ommlds/cli/sessions/chat/{chat → drivers}/ai/types.py +9 -0
  49. ommlds/cli/sessions/chat/drivers/configs.py +25 -0
  50. ommlds/cli/sessions/chat/drivers/events/inject.py +27 -0
  51. ommlds/cli/sessions/chat/drivers/events/injection.py +14 -0
  52. ommlds/cli/sessions/chat/drivers/events/manager.py +16 -0
  53. ommlds/cli/sessions/chat/drivers/events/types.py +38 -0
  54. ommlds/cli/sessions/chat/drivers/impl.py +50 -0
  55. ommlds/cli/sessions/chat/drivers/inject.py +70 -0
  56. ommlds/cli/sessions/chat/{chat → drivers}/state/configs.py +2 -0
  57. ommlds/cli/sessions/chat/drivers/state/ids.py +25 -0
  58. ommlds/cli/sessions/chat/drivers/state/inject.py +83 -0
  59. ommlds/cli/sessions/chat/{chat → drivers}/state/inmemory.py +0 -4
  60. ommlds/cli/sessions/chat/{chat → drivers}/state/storage.py +17 -10
  61. ommlds/cli/sessions/chat/{chat → drivers}/state/types.py +10 -5
  62. ommlds/cli/sessions/chat/{tools → drivers/tools}/configs.py +2 -2
  63. ommlds/cli/sessions/chat/drivers/tools/confirmation.py +44 -0
  64. ommlds/cli/sessions/chat/drivers/tools/errorhandling.py +39 -0
  65. ommlds/cli/sessions/chat/{tools → drivers/tools}/execution.py +3 -4
  66. ommlds/cli/sessions/chat/{tools → drivers/tools}/fs/inject.py +3 -3
  67. ommlds/cli/sessions/chat/{tools → drivers/tools}/inject.py +7 -12
  68. ommlds/cli/sessions/chat/{tools → drivers/tools}/injection.py +5 -5
  69. ommlds/cli/sessions/chat/{tools → drivers/tools}/rendering.py +3 -3
  70. ommlds/cli/sessions/chat/{tools → drivers/tools}/todo/inject.py +3 -3
  71. ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/tools.py +1 -1
  72. ommlds/cli/sessions/chat/drivers/types.py +31 -0
  73. ommlds/cli/sessions/chat/{chat → drivers}/user/configs.py +0 -3
  74. ommlds/cli/sessions/chat/drivers/user/inject.py +41 -0
  75. ommlds/cli/sessions/chat/facades/__init__.py +0 -0
  76. ommlds/cli/sessions/chat/facades/commands/__init__.py +0 -0
  77. ommlds/cli/sessions/chat/facades/commands/base.py +83 -0
  78. ommlds/cli/sessions/chat/facades/commands/configs.py +9 -0
  79. ommlds/cli/sessions/chat/facades/commands/inject.py +41 -0
  80. ommlds/cli/sessions/chat/facades/commands/injection.py +15 -0
  81. ommlds/cli/sessions/chat/facades/commands/manager.py +59 -0
  82. ommlds/cli/sessions/chat/facades/commands/simple.py +34 -0
  83. ommlds/cli/sessions/chat/facades/commands/types.py +13 -0
  84. ommlds/cli/sessions/chat/facades/configs.py +11 -0
  85. ommlds/cli/sessions/chat/facades/facade.py +26 -0
  86. ommlds/cli/sessions/chat/facades/inject.py +35 -0
  87. ommlds/cli/sessions/chat/facades/ui.py +34 -0
  88. ommlds/cli/sessions/chat/inject.py +8 -31
  89. ommlds/cli/sessions/chat/interfaces/__init__.py +0 -0
  90. ommlds/cli/sessions/chat/interfaces/bare/__init__.py +0 -0
  91. ommlds/cli/sessions/chat/interfaces/bare/configs.py +15 -0
  92. ommlds/cli/sessions/chat/interfaces/bare/inject.py +69 -0
  93. ommlds/cli/sessions/chat/interfaces/bare/interactive.py +49 -0
  94. ommlds/cli/sessions/chat/interfaces/bare/oneshot.py +21 -0
  95. ommlds/cli/sessions/chat/{tools/confirmation.py → interfaces/bare/tools.py} +3 -22
  96. ommlds/cli/sessions/chat/interfaces/base.py +13 -0
  97. ommlds/cli/sessions/chat/interfaces/configs.py +11 -0
  98. ommlds/cli/sessions/chat/interfaces/inject.py +29 -0
  99. ommlds/cli/sessions/chat/interfaces/textual/__init__.py +0 -0
  100. ommlds/cli/sessions/chat/interfaces/textual/app.py +310 -0
  101. ommlds/cli/sessions/chat/interfaces/textual/configs.py +11 -0
  102. ommlds/cli/sessions/chat/interfaces/textual/facades.py +19 -0
  103. ommlds/cli/sessions/chat/interfaces/textual/inject.py +97 -0
  104. ommlds/cli/sessions/chat/interfaces/textual/interface.py +24 -0
  105. ommlds/cli/sessions/chat/interfaces/textual/styles/__init__.py +29 -0
  106. ommlds/cli/sessions/chat/interfaces/textual/styles/input.tcss +53 -0
  107. ommlds/cli/sessions/chat/interfaces/textual/styles/markdown.tcss +7 -0
  108. ommlds/cli/sessions/chat/interfaces/textual/styles/messages.tcss +157 -0
  109. ommlds/cli/sessions/chat/interfaces/textual/tools.py +38 -0
  110. ommlds/cli/sessions/chat/interfaces/textual/widgets/__init__.py +0 -0
  111. ommlds/cli/sessions/chat/interfaces/textual/widgets/input.py +36 -0
  112. ommlds/cli/sessions/chat/interfaces/textual/widgets/messages.py +197 -0
  113. ommlds/cli/sessions/chat/session.py +8 -13
  114. ommlds/cli/sessions/completion/configs.py +3 -4
  115. ommlds/cli/sessions/completion/inject.py +1 -2
  116. ommlds/cli/sessions/completion/session.py +4 -8
  117. ommlds/cli/sessions/configs.py +10 -0
  118. ommlds/cli/sessions/embedding/configs.py +3 -4
  119. ommlds/cli/sessions/embedding/inject.py +1 -2
  120. ommlds/cli/sessions/embedding/session.py +4 -8
  121. ommlds/cli/sessions/inject.py +15 -15
  122. ommlds/cli/state/storage.py +7 -1
  123. ommlds/minichain/__init__.py +161 -38
  124. ommlds/minichain/_dataclasses.py +20452 -0
  125. ommlds/minichain/_typedvalues.py +11 -4
  126. ommlds/minichain/backends/impls/anthropic/names.py +3 -3
  127. ommlds/minichain/backends/impls/anthropic/protocol.py +2 -2
  128. ommlds/minichain/backends/impls/anthropic/stream.py +1 -1
  129. ommlds/minichain/backends/impls/cerebras/__init__.py +0 -0
  130. ommlds/minichain/backends/impls/cerebras/chat.py +80 -0
  131. ommlds/minichain/backends/impls/cerebras/names.py +45 -0
  132. ommlds/minichain/backends/impls/cerebras/protocol.py +143 -0
  133. ommlds/minichain/backends/impls/cerebras/stream.py +125 -0
  134. ommlds/minichain/backends/impls/duckduckgo/search.py +5 -1
  135. ommlds/minichain/backends/impls/google/names.py +6 -0
  136. ommlds/minichain/backends/impls/google/stream.py +1 -1
  137. ommlds/minichain/backends/impls/google/tools.py +2 -2
  138. ommlds/minichain/backends/impls/groq/chat.py +2 -0
  139. ommlds/minichain/backends/impls/groq/protocol.py +2 -2
  140. ommlds/minichain/backends/impls/groq/stream.py +3 -1
  141. ommlds/minichain/backends/impls/huggingface/repos.py +1 -5
  142. ommlds/minichain/backends/impls/llamacpp/chat.py +6 -3
  143. ommlds/minichain/backends/impls/llamacpp/completion.py +7 -3
  144. ommlds/minichain/backends/impls/llamacpp/stream.py +6 -3
  145. ommlds/minichain/backends/impls/mlx/chat.py +6 -3
  146. ommlds/minichain/backends/impls/ollama/chat.py +51 -57
  147. ommlds/minichain/backends/impls/ollama/protocol.py +144 -0
  148. ommlds/minichain/backends/impls/openai/format.py +4 -3
  149. ommlds/minichain/backends/impls/openai/names.py +3 -1
  150. ommlds/minichain/backends/impls/openai/stream.py +33 -1
  151. ommlds/minichain/backends/impls/sentencepiece/tokens.py +9 -6
  152. ommlds/minichain/backends/impls/tinygrad/chat.py +7 -4
  153. ommlds/minichain/backends/impls/tokenizers/tokens.py +9 -6
  154. ommlds/minichain/backends/impls/transformers/sentence.py +5 -2
  155. ommlds/minichain/backends/impls/transformers/tokens.py +9 -6
  156. ommlds/minichain/backends/impls/transformers/transformers.py +10 -8
  157. ommlds/minichain/backends/strings/resolving.py +1 -1
  158. ommlds/minichain/chat/content.py +42 -0
  159. ommlds/minichain/chat/messages.py +43 -39
  160. ommlds/minichain/chat/stream/joining.py +36 -12
  161. ommlds/minichain/chat/stream/types.py +1 -1
  162. ommlds/minichain/chat/templating.py +3 -3
  163. ommlds/minichain/content/__init__.py +19 -3
  164. ommlds/minichain/content/_marshal.py +181 -55
  165. ommlds/minichain/content/code.py +26 -0
  166. ommlds/minichain/content/composite.py +28 -0
  167. ommlds/minichain/content/content.py +27 -0
  168. ommlds/minichain/content/dynamic.py +12 -0
  169. ommlds/minichain/content/emphasis.py +27 -0
  170. ommlds/minichain/content/images.py +2 -2
  171. ommlds/minichain/content/json.py +2 -2
  172. ommlds/minichain/content/link.py +13 -0
  173. ommlds/minichain/content/markdown.py +12 -0
  174. ommlds/minichain/content/metadata.py +10 -0
  175. ommlds/minichain/content/namespaces.py +8 -0
  176. ommlds/minichain/content/placeholders.py +10 -9
  177. ommlds/minichain/content/quote.py +26 -0
  178. ommlds/minichain/content/raw.py +49 -0
  179. ommlds/minichain/content/recursive.py +12 -0
  180. ommlds/minichain/content/section.py +26 -0
  181. ommlds/minichain/content/sequence.py +17 -3
  182. ommlds/minichain/content/standard.py +32 -0
  183. ommlds/minichain/content/tag.py +28 -0
  184. ommlds/minichain/content/templates.py +13 -0
  185. ommlds/minichain/content/text.py +2 -2
  186. ommlds/minichain/content/transform/__init__.py +0 -0
  187. ommlds/minichain/content/transform/json.py +55 -0
  188. ommlds/minichain/content/transform/markdown.py +8 -0
  189. ommlds/minichain/content/transform/materialize.py +51 -0
  190. ommlds/minichain/content/transform/metadata.py +16 -0
  191. ommlds/minichain/content/{prepare.py → transform/prepare.py} +10 -15
  192. ommlds/minichain/content/transform/recursive.py +97 -0
  193. ommlds/minichain/content/transform/standard.py +43 -0
  194. ommlds/minichain/content/{transforms → transform}/stringify.py +1 -7
  195. ommlds/minichain/content/transform/strings.py +33 -0
  196. ommlds/minichain/content/transform/templates.py +25 -0
  197. ommlds/minichain/content/visitors.py +231 -0
  198. ommlds/minichain/lib/fs/tools/read.py +1 -1
  199. ommlds/minichain/lib/fs/tools/recursivels/rendering.py +1 -1
  200. ommlds/minichain/lib/fs/tools/recursivels/running.py +1 -1
  201. ommlds/minichain/lib/todo/tools/write.py +2 -1
  202. ommlds/minichain/lib/todo/types.py +1 -1
  203. ommlds/minichain/metadata.py +56 -2
  204. ommlds/minichain/resources.py +22 -1
  205. ommlds/minichain/services/README.md +154 -0
  206. ommlds/minichain/services/__init__.py +6 -2
  207. ommlds/minichain/services/_marshal.py +46 -10
  208. ommlds/minichain/services/_origclasses.py +11 -0
  209. ommlds/minichain/services/_typedvalues.py +8 -3
  210. ommlds/minichain/services/requests.py +73 -3
  211. ommlds/minichain/services/responses.py +73 -3
  212. ommlds/minichain/services/services.py +9 -0
  213. ommlds/minichain/stream/services.py +24 -1
  214. ommlds/minichain/text/applypatch.py +2 -1
  215. ommlds/minichain/text/toolparsing/llamacpp/types.py +1 -1
  216. ommlds/minichain/tokens/specials.py +1 -1
  217. ommlds/minichain/tools/execution/catalog.py +1 -1
  218. ommlds/minichain/tools/execution/errorhandling.py +36 -0
  219. ommlds/minichain/tools/execution/errors.py +2 -2
  220. ommlds/minichain/tools/execution/executors.py +1 -1
  221. ommlds/minichain/tools/fns.py +1 -1
  222. ommlds/minichain/tools/jsonschema.py +2 -2
  223. ommlds/minichain/tools/reflect.py +6 -6
  224. ommlds/minichain/tools/types.py +12 -15
  225. ommlds/minichain/vectors/_marshal.py +1 -1
  226. ommlds/minichain/vectors/embeddings.py +1 -1
  227. ommlds/minichain/wrappers/__init__.py +7 -0
  228. ommlds/minichain/wrappers/firstinwins.py +144 -0
  229. ommlds/minichain/wrappers/instrument.py +146 -0
  230. ommlds/minichain/wrappers/retry.py +168 -0
  231. ommlds/minichain/wrappers/services.py +98 -0
  232. ommlds/minichain/wrappers/stream.py +57 -0
  233. ommlds/nanochat/rustbpe/README.md +9 -0
  234. ommlds/nanochat/tokenizers.py +40 -6
  235. ommlds/specs/mcp/clients.py +146 -0
  236. ommlds/specs/mcp/protocol.py +123 -18
  237. ommlds/tools/git.py +82 -65
  238. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/METADATA +13 -11
  239. ommlds-0.0.0.dev503.dist-info/RECORD +520 -0
  240. ommlds/cli/sessions/chat/chat/state/inject.py +0 -36
  241. ommlds/cli/sessions/chat/chat/user/inject.py +0 -62
  242. ommlds/cli/sessions/chat/chat/user/interactive.py +0 -31
  243. ommlds/cli/sessions/chat/chat/user/oneshot.py +0 -25
  244. ommlds/cli/sessions/chat/chat/user/types.py +0 -15
  245. ommlds/cli/sessions/chat/driver.py +0 -43
  246. ommlds/minichain/content/materialize.py +0 -196
  247. ommlds/minichain/content/simple.py +0 -47
  248. ommlds/minichain/content/transforms/base.py +0 -46
  249. ommlds/minichain/content/transforms/interleave.py +0 -70
  250. ommlds/minichain/content/transforms/squeeze.py +0 -72
  251. ommlds/minichain/content/transforms/strings.py +0 -24
  252. ommlds/minichain/content/types.py +0 -43
  253. ommlds/minichain/stream/wrap.py +0 -62
  254. ommlds-0.0.0.dev480.dist-info/RECORD +0 -427
  255. /ommlds/cli/sessions/chat/{chat → drivers}/__init__.py +0 -0
  256. /ommlds/cli/sessions/chat/{chat → drivers}/ai/__init__.py +0 -0
  257. /ommlds/cli/sessions/chat/{chat → drivers}/ai/injection.py +0 -0
  258. /ommlds/cli/sessions/chat/{chat/state → drivers/events}/__init__.py +0 -0
  259. /ommlds/cli/sessions/chat/{chat/user → drivers/phases}/__init__.py +0 -0
  260. /ommlds/cli/sessions/chat/{phases → drivers/phases}/inject.py +0 -0
  261. /ommlds/cli/sessions/chat/{phases → drivers/phases}/injection.py +0 -0
  262. /ommlds/cli/sessions/chat/{phases → drivers/phases}/manager.py +0 -0
  263. /ommlds/cli/sessions/chat/{phases → drivers/phases}/types.py +0 -0
  264. /ommlds/cli/sessions/chat/{phases → drivers/state}/__init__.py +0 -0
  265. /ommlds/cli/sessions/chat/{tools → drivers/tools}/__init__.py +0 -0
  266. /ommlds/cli/sessions/chat/{tools → drivers/tools}/fs/__init__.py +0 -0
  267. /ommlds/cli/sessions/chat/{tools → drivers/tools}/fs/configs.py +0 -0
  268. /ommlds/cli/sessions/chat/{tools → drivers/tools}/todo/__init__.py +0 -0
  269. /ommlds/cli/sessions/chat/{tools → drivers/tools}/todo/configs.py +0 -0
  270. /ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/__init__.py +0 -0
  271. /ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/configs.py +0 -0
  272. /ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/inject.py +0 -0
  273. /ommlds/{minichain/content/transforms → cli/sessions/chat/drivers/user}/__init__.py +0 -0
  274. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/WHEEL +0 -0
  275. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/entry_points.txt +0 -0
  276. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/licenses/LICENSE +0 -0
  277. {ommlds-0.0.0.dev480.dist-info → ommlds-0.0.0.dev503.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,8 @@
1
+ """
2
+ FIXME:
3
+ - everything lol
4
+ - can this just do what metadata does
5
+ """
1
6
  import typing as ta
2
7
 
3
8
  from omlish import check
@@ -22,10 +27,21 @@ def _is_rr_rty(rty: rfl.Type) -> bool:
22
27
  )
23
28
 
24
29
 
25
- def _get_tv_fld(rty: rfl.Type) -> dc.Field:
30
+ class _RrFlds(ta.NamedTuple):
31
+ v: dc.Field
32
+ tv: dc.Field
33
+ md: dc.Field
34
+
35
+
36
+ def _get_rr_flds(rty: rfl.Type) -> _RrFlds:
26
37
  flds = col.make_map_by(lambda f: f.name, dc.fields(check.not_none(rfl.get_concrete_type(rty))), strict=True)
27
- flds.pop('v')
28
- return check.single(flds.values())
38
+ v_fld = flds.pop('v')
39
+ md_fld = flds.pop('_metadata')
40
+ return _RrFlds(
41
+ v=v_fld,
42
+ tv=check.single(flds.values()),
43
+ md=md_fld,
44
+ )
29
45
 
30
46
 
31
47
  ##
@@ -34,7 +50,7 @@ def _get_tv_fld(rty: rfl.Type) -> dc.Field:
34
50
  @dc.dataclass(frozen=True)
35
51
  class _RequestResponseMarshaler(msh.Marshaler):
36
52
  rty: rfl.Type
37
- tv_fld: dc.Field
53
+ rr_flds: _RrFlds
38
54
  v_m: msh.Marshaler | None
39
55
 
40
56
  def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
@@ -51,9 +67,14 @@ class _RequestResponseMarshaler(msh.Marshaler):
51
67
  else:
52
68
  v_v = self.v_m.marshal(ctx, o.v)
53
69
 
70
+ md_fmd = self.rr_flds.md.metadata[msh.FieldMetadata]
71
+ md_m = md_fmd.marshaler_factory.make_marshaler(ctx.marshal_factory_context, self.rr_flds.md.type)() # FIXME
72
+ md_v = md_m.marshal(ctx, o._metadata) # noqa
73
+
54
74
  return {
55
75
  'v': v_v,
56
- **({lang.strip_prefix(self.tv_fld.name, '_'): tv_v} if tv_v else {}),
76
+ **({lang.strip_prefix(self.rr_flds.tv.name, '_'): tv_v} if tv_v else {}),
77
+ **({'metadata': md_v} if md_v else {}),
57
78
  }
58
79
 
59
80
 
@@ -76,7 +97,7 @@ class _RequestResponseMarshalerFactory(msh.MarshalerFactory):
76
97
  v_m = ctx.make_marshaler(v_rty)
77
98
  return _RequestResponseMarshaler(
78
99
  rty,
79
- _get_tv_fld(rty),
100
+ _get_rr_flds(rty),
80
101
  v_m,
81
102
  )
82
103
 
@@ -89,9 +110,10 @@ class _RequestResponseMarshalerFactory(msh.MarshalerFactory):
89
110
  @dc.dataclass(frozen=True)
90
111
  class _RequestResponseUnmarshaler(msh.Unmarshaler):
91
112
  rty: rfl.Type
92
- tv_fld: dc.Field
113
+ rr_flds: _RrFlds
93
114
  v_u: msh.Unmarshaler
94
115
  tv_u: msh.Unmarshaler
116
+ md_u: msh.Unmarshaler
95
117
 
96
118
  def unmarshal(self, ctx: msh.UnmarshalContext, v: msh.Value) -> ta.Any:
97
119
  dct = dict(check.isinstance(v, ta.Mapping))
@@ -99,9 +121,14 @@ class _RequestResponseUnmarshaler(msh.Unmarshaler):
99
121
  v_v = dct.pop('v')
100
122
  v = self.v_u.unmarshal(ctx, v_v)
101
123
 
124
+ if md_v := dct.pop('metadata', None):
125
+ md = self.md_u.unmarshal(ctx, md_v)
126
+ else:
127
+ md = []
128
+
102
129
  tvs: ta.Any
103
130
  if dct:
104
- tv_vs = dct.pop(lang.strip_prefix(self.tv_fld.name, '_'))
131
+ tv_vs = dct.pop(lang.strip_prefix(self.rr_flds.tv.name, '_'))
105
132
  tvs = self.tv_u.unmarshal(ctx, tv_vs)
106
133
  else:
107
134
  tvs = []
@@ -109,7 +136,7 @@ class _RequestResponseUnmarshaler(msh.Unmarshaler):
109
136
  check.empty(dct)
110
137
 
111
138
  cty = rfl.get_concrete_type(self.rty)
112
- return cty(v, tvs) # type: ignore
139
+ return cty(v, tvs, _metadata=md) # type: ignore
113
140
 
114
141
 
115
142
  class _RequestResponseUnmarshalerFactory(msh.UnmarshalerFactory):
@@ -123,15 +150,24 @@ class _RequestResponseUnmarshalerFactory(msh.UnmarshalerFactory):
123
150
  else:
124
151
  # FIXME: ...
125
152
  raise TypeError(rty)
153
+
154
+ rr_flds = _get_rr_flds(rty)
155
+
126
156
  tv_types_set = check.isinstance(tv_rty, rfl.Union).args
127
157
  tv_ta = tv.TypedValues[ta.Union[*tv_types_set]] # type: ignore
128
158
  tv_u = ctx.make_unmarshaler(tv_ta)
159
+
129
160
  v_u = ctx.make_unmarshaler(v_rty)
161
+
162
+ md_fmd = rr_flds.md.metadata[msh.FieldMetadata]
163
+ md_u = md_fmd.unmarshaler_factory.make_unmarshaler(ctx, rr_flds.md.type)() # FIXME
164
+
130
165
  return _RequestResponseUnmarshaler(
131
166
  rty,
132
- _get_tv_fld(rty),
167
+ _get_rr_flds(rty),
133
168
  v_u,
134
169
  tv_u,
170
+ md_u,
135
171
  )
136
172
 
137
173
  return inner
@@ -43,3 +43,14 @@ class _OrigClassCapture:
43
43
  """Enforces that __orig_class__ has only been set once."""
44
44
 
45
45
  return check.single(object.__getattribute__(self, '__captured_orig_classes__'))
46
+
47
+
48
+ def confer_orig_class(src, dst):
49
+ if src is not dst:
50
+ try:
51
+ oc = src.__orig_class__
52
+ except AttributeError:
53
+ pass
54
+ else:
55
+ dst.__orig_class__ = oc
56
+ return dst
@@ -45,14 +45,19 @@ class _TypedValues(
45
45
  lang.Abstract,
46
46
  ta.Generic[TypedValueT],
47
47
  ):
48
- __typed_values_class__: ta.ClassVar[type[tv.TypedValue]]
48
+ """
49
+ The reason this is so complicated compared to any other TypedValues field (like metadata) is that the real set of
50
+ TypedValue types it accepts is known only via __orig_class__.
51
+ """
52
+
53
+ __typed_values_base__: ta.ClassVar[type[tv.TypedValue]]
49
54
 
50
55
  def __init_subclass__(cls, **kwargs: ta.Any) -> None:
51
56
  super().__init_subclass__(**kwargs)
52
57
 
53
58
  tvt = _get_typed_values_type_arg(cls)
54
59
  tvct = rfl.get_concrete_type(tvt, use_type_var_bound=True)
55
- cls.__typed_values_class__ = check.issubclass(check.isinstance(tvct, type), tv.TypedValue)
60
+ cls.__typed_values_base__ = check.issubclass(check.isinstance(tvct, type), tv.TypedValue)
56
61
 
57
62
  #
58
63
 
@@ -77,7 +82,7 @@ class _TypedValues(
77
82
 
78
83
  tv_types_set = frozenset(tv.reflect_typed_values_impls(tvt))
79
84
  tv_types = tuple(sorted(
80
- [check.issubclass(c, self.__typed_values_class__) for c in tv_types_set],
85
+ [check.issubclass(c, self.__typed_values_base__) for c in tv_types_set],
81
86
  key=lambda c: c.__qualname__,
82
87
  ))
83
88
 
@@ -6,8 +6,12 @@ from omlish import lang
6
6
  from omlish import typedvalues as tv
7
7
 
8
8
  from .._typedvalues import _tv_field_metadata
9
+ from ..metadata import CommonMetadata
10
+ from ..metadata import Metadata
11
+ from ..metadata import MetadataContainerDataclass
9
12
  from ..types import Option
10
13
  from ..types import OptionT_co
14
+ from ._origclasses import confer_orig_class
11
15
  from ._typedvalues import _TypedValues
12
16
 
13
17
 
@@ -19,6 +23,17 @@ OptionU = ta.TypeVar('OptionU', bound=Option)
19
23
  ##
20
24
 
21
25
 
26
+ class RequestMetadata(Metadata, lang.Abstract):
27
+ pass
28
+
29
+
30
+ RequestMetadatas: ta.TypeAlias = RequestMetadata | CommonMetadata
31
+
32
+
33
+ ##
34
+
35
+
36
+ @ta.final
22
37
  @dc.dataclass(frozen=True)
23
38
  @dc.extra_class_params(
24
39
  allow_dynamic_dunder_attrs=True,
@@ -26,11 +41,32 @@ OptionU = ta.TypeVar('OptionU', bound=Option)
26
41
  )
27
42
  class Request( # type: ignore[type-var] # FIXME: _TypedValues param is invariant
28
43
  _TypedValues[OptionT_co],
44
+ MetadataContainerDataclass[RequestMetadatas],
29
45
  lang.Final,
30
46
  ta.Generic[V_co, OptionT_co],
31
47
  ):
48
+ """
49
+ Universal service request, comprised of:
50
+ - a value of type `V_co`
51
+ - a sequence of options of type `OptionT_co`
52
+ - metadata of type `RequestMetadatas`
53
+
54
+ Refer to the package README.md for an explanation of its type var variance.
55
+
56
+ This class is final, but each instance's `__orig_class__` (if present) is significant. It is encouraged to construct
57
+ these through a pre-parameterized type alias, and the provided `with_` methods should be used rather than
58
+ `dc.replace` (as they will propagate `__orig_class__`).
59
+ """
60
+
61
+ #
62
+
32
63
  v: V_co # type: ignore[misc] # FIXME: Cannot use a covariant type variable as a parameter
33
64
 
65
+ def with_v(self, v: V_co) -> ta.Self: # type: ignore[misc]
66
+ return confer_orig_class(self, dc.replace(self, v=v))
67
+
68
+ #
69
+
34
70
  _options: ta.Sequence[OptionT_co] = dc.field(
35
71
  default=(),
36
72
  metadata=_tv_field_metadata(
@@ -43,13 +79,47 @@ class Request( # type: ignore[type-var] # FIXME: _TypedValues param is invaria
43
79
  def options(self) -> tv.TypedValues[OptionT_co]:
44
80
  return check.isinstance(self._options, tv.TypedValues)
45
81
 
46
- def with_options(self, *options: OptionU, override: bool = False) -> 'Request[V_co, OptionT_co | OptionU]':
47
- return dc.replace(self, _options=self.options.update(*options, override=override))
48
-
49
82
  @property
50
83
  def _typed_values(self) -> tv.TypedValues[OptionT_co]:
51
84
  return check.isinstance(self._options, tv.TypedValues)
52
85
 
86
+ def with_options(
87
+ self,
88
+ *add: OptionU,
89
+ discard: ta.Iterable[type] | None = None,
90
+ override: bool = False,
91
+ ) -> 'Request[V_co, OptionT_co | OptionU]':
92
+ new = (old := self.options).update(
93
+ *add,
94
+ discard=discard,
95
+ override=override,
96
+ )
97
+
98
+ if new is old:
99
+ return self
100
+
101
+ return confer_orig_class(self, dc.replace(self, _options=new))
102
+
103
+ #
104
+
105
+ _metadata: ta.Sequence[RequestMetadatas] = dc.field(
106
+ default=(),
107
+ kw_only=True,
108
+ repr=False,
109
+ )
110
+
111
+ MetadataContainerDataclass._configure_metadata_field(_metadata, RequestMetadatas) # noqa
112
+
113
+ def with_metadata(
114
+ self,
115
+ *add: RequestMetadatas,
116
+ discard: ta.Iterable[type] | None = None,
117
+ override: bool = False,
118
+ ) -> ta.Self:
119
+ return confer_orig_class(self, super().with_metadata(*add, discard=discard, override=override))
120
+
121
+ #
122
+
53
123
  def validate(self) -> ta.Self:
54
124
  self._check_typed_values()
55
125
  return self
@@ -6,8 +6,12 @@ from omlish import lang
6
6
  from omlish import typedvalues as tv
7
7
 
8
8
  from .._typedvalues import _tv_field_metadata
9
+ from ..metadata import CommonMetadata
10
+ from ..metadata import Metadata
11
+ from ..metadata import MetadataContainerDataclass
9
12
  from ..types import Output
10
13
  from ..types import OutputT_contra
14
+ from ._origclasses import confer_orig_class
11
15
  from ._typedvalues import _TypedValues
12
16
 
13
17
 
@@ -17,6 +21,17 @@ V_co = ta.TypeVar('V_co', covariant=True)
17
21
  ##
18
22
 
19
23
 
24
+ class ResponseMetadata(Metadata, lang.Abstract):
25
+ pass
26
+
27
+
28
+ ResponseMetadatas: ta.TypeAlias = ResponseMetadata | CommonMetadata
29
+
30
+
31
+ ##
32
+
33
+
34
+ @ta.final
20
35
  @dc.dataclass(frozen=True)
21
36
  @dc.extra_class_params(
22
37
  allow_dynamic_dunder_attrs=True,
@@ -24,11 +39,32 @@ V_co = ta.TypeVar('V_co', covariant=True)
24
39
  )
25
40
  class Response( # type: ignore[type-var] # FIXME: _TypedValues param is invariant
26
41
  _TypedValues[OutputT_contra],
42
+ MetadataContainerDataclass[ResponseMetadatas],
27
43
  lang.Final,
28
44
  ta.Generic[V_co, OutputT_contra],
29
45
  ):
46
+ """
47
+ Universal service response, comprised of:
48
+ - a value of type `V_co`
49
+ - a sequence of outputs of type `OutputT_contra`
50
+ - metadata of type `ResponseMetadatas`
51
+
52
+ Refer to the package README.md for an explanation of its type var variance.
53
+
54
+ This class is final, but each instance's `__orig_class__` (if present) is significant. It is encouraged to construct
55
+ these through a pre-parameterized type alias, and the provided `with_` methods should be used rather than
56
+ `dc.replace` (as they will propagate `__orig_class__`).
57
+ """
58
+
59
+ #
60
+
30
61
  v: V_co # type: ignore[misc] # FIXME: Cannot use a covariant type variable as a parameter
31
62
 
63
+ def with_v(self, v: V_co) -> ta.Self: # type: ignore[misc]
64
+ return confer_orig_class(self, dc.replace(self, v=v))
65
+
66
+ #
67
+
32
68
  _outputs: ta.Sequence[OutputT_contra] = dc.field(
33
69
  default=(),
34
70
  metadata=_tv_field_metadata(
@@ -41,13 +77,47 @@ class Response( # type: ignore[type-var] # FIXME: _TypedValues param is invari
41
77
  def outputs(self) -> tv.TypedValues[OutputT_contra]:
42
78
  return check.isinstance(self._outputs, tv.TypedValues)
43
79
 
44
- def with_outputs(self, *outputs: OutputT_contra, override: bool = False) -> ta.Self:
45
- return dc.replace(self, _outputs=self.outputs.update(*outputs, override=override))
46
-
47
80
  @property
48
81
  def _typed_values(self) -> tv.TypedValues[OutputT_contra]:
49
82
  return check.isinstance(self._outputs, tv.TypedValues)
50
83
 
84
+ def with_outputs(
85
+ self,
86
+ *add: OutputT_contra,
87
+ discard: ta.Iterable[type] | None = None,
88
+ override: bool = False,
89
+ ) -> ta.Self:
90
+ new = (old := self.outputs).update(
91
+ *add,
92
+ discard=discard,
93
+ override=override,
94
+ )
95
+
96
+ if new is old:
97
+ return self
98
+
99
+ return confer_orig_class(self, dc.replace(self, _outputs=new))
100
+
101
+ #
102
+
103
+ _metadata: ta.Sequence[ResponseMetadatas] = dc.field(
104
+ default=(),
105
+ kw_only=True,
106
+ repr=False,
107
+ )
108
+
109
+ MetadataContainerDataclass._configure_metadata_field(_metadata, ResponseMetadatas) # noqa
110
+
111
+ def with_metadata(
112
+ self,
113
+ *add: ResponseMetadatas,
114
+ discard: ta.Iterable[type] | None = None,
115
+ override: bool = False,
116
+ ) -> ta.Self:
117
+ return confer_orig_class(self, super().with_metadata(*add, discard=discard, override=override))
118
+
119
+ #
120
+
51
121
  def validate(self) -> ta.Self:
52
122
  self._check_typed_values()
53
123
  return self
@@ -11,4 +11,13 @@ from .responses import ResponseT_co
11
11
 
12
12
  @ta.runtime_checkable
13
13
  class Service(lang.ProtocolForbiddenAsBaseClass, ta.Protocol[RequestT_contra, ResponseT_co]):
14
+ """
15
+ Universal service protocol, comprised of a single method `invoke`, accepting a request of type `RequestT_contra` and
16
+ returning a response of type `ResponseT_co`.
17
+
18
+ Refer to the package README.md for an explanation of its type var variance.
19
+
20
+ This class is final, but each instance's `__orig_class__` (if present) is significant.
21
+ """
22
+
14
23
  def invoke(self, request: RequestT_contra) -> ta.Awaitable[ResponseT_co]: ...
@@ -1,3 +1,7 @@
1
+ """
2
+ TODO:
3
+ - new_stream_response carry TypeAlias __orig_type__ somehow
4
+ """
1
5
  import abc
2
6
  import itertools
3
7
  import types
@@ -104,17 +108,23 @@ class _StreamServiceResponse(StreamResponseIterator[V, OutputT]):
104
108
  return _StreamServiceResponse._Emit(self._ssr, item)
105
109
 
106
110
  _state: ta.Literal['new', 'running', 'closed'] = 'new'
111
+
107
112
  _sink: _Sink[V]
108
- _a: ta.Any
113
+
109
114
  _cr: ta.Any
115
+ _a: ta.Any
116
+ _g: ta.Any
110
117
 
111
118
  async def __aenter__(self) -> ta.Self:
112
119
  check.state(self._state == 'new')
113
120
  self._state = 'running'
121
+
114
122
  self._sink = _StreamServiceResponse._Sink(self)
123
+
115
124
  self._cr = self._fn(self._sink)
116
125
  self._a = self._cr.__await__()
117
126
  self._g = iter(self._a)
127
+
118
128
  return self
119
129
 
120
130
  @types.coroutine
@@ -123,8 +133,10 @@ class _StreamServiceResponse(StreamResponseIterator[V, OutputT]):
123
133
  self._state = 'closed'
124
134
  if old_state != 'running':
125
135
  return
136
+
126
137
  if self._cr.cr_running or self._cr.cr_suspended:
127
138
  cex = StreamServiceCancelledError()
139
+
128
140
  i = None
129
141
  for n in itertools.count():
130
142
  try:
@@ -132,13 +144,18 @@ class _StreamServiceResponse(StreamResponseIterator[V, OutputT]):
132
144
  x = self._g.throw(cex)
133
145
  else:
134
146
  x = self._g.send(i)
147
+
135
148
  except StreamServiceCancelledError as cex2:
136
149
  if cex2 is cex:
137
150
  break
151
+
138
152
  raise
153
+
139
154
  i = yield x
155
+
140
156
  if self._cr.cr_running:
141
157
  raise RuntimeError(f'Coroutine {self._cr!r} not terminated')
158
+
142
159
  if self._g is not self._a:
143
160
  self._g.close()
144
161
  self._a.close()
@@ -156,15 +173,18 @@ class _StreamServiceResponse(StreamResponseIterator[V, OutputT]):
156
173
  @types.coroutine
157
174
  def _anext(self):
158
175
  check.state(self._state == 'running')
176
+
159
177
  i = None
160
178
  while True:
161
179
  try:
162
180
  x = self._g.send(i)
181
+
163
182
  except StopIteration as e:
164
183
  if e.value is not None:
165
184
  self._outputs = tv.TypedValues(*check.isinstance(e.value, ta.Sequence))
166
185
  else:
167
186
  self._outputs = tv.TypedValues()
187
+
168
188
  raise StopAsyncIteration from None
169
189
 
170
190
  if isinstance(x, _StreamServiceResponse._Emit) and x.ssr is self:
@@ -200,11 +220,14 @@ async def new_stream_response(
200
220
  ssr = _StreamServiceResponse(fn)
201
221
 
202
222
  v = rs.new_managed(await rs.enter_async_context(ssr))
223
+
203
224
  try:
204
225
  return StreamResponse(v, outputs or [])
226
+
205
227
  except BaseException: # noqa
206
228
  # The StreamResponse ctor can raise - for example in `_tv_field_coercer` - in which case we need to clean up the
207
229
  # resources ref we have already allocated before reraising.
208
230
  async with v:
209
231
  pass
232
+
210
233
  raise
@@ -20,11 +20,12 @@
20
20
  A self-contained **pure-Python 3.9+** utility for applying human-readable "pseudo-diff" patch files to a collection of
21
21
  text files.
22
22
  """
23
- import dataclasses as dc
24
23
  import enum
25
24
  import pathlib
26
25
  import typing as ta
27
26
 
27
+ from omlish import dataclasses as dc
28
+
28
29
 
29
30
  ##
30
31
  # Domain objects
@@ -1,4 +1,4 @@
1
- import dataclasses as dc
1
+ from omlish import dataclasses as dc
2
2
 
3
3
 
4
4
  ##
@@ -1,7 +1,7 @@
1
- import dataclasses as dc
2
1
  import typing as ta
3
2
 
4
3
  from omlish import check
4
+ from omlish import dataclasses as dc
5
5
  from omlish import lang
6
6
 
7
7
  from .types import NonSpecialToken
@@ -4,7 +4,7 @@ from omlish import check
4
4
  from omlish import dataclasses as dc
5
5
  from omlish import lang
6
6
 
7
- from ...content.types import Content
7
+ from ...content.content import Content
8
8
  from ..fns import ToolFn
9
9
  from ..types import ToolSpec
10
10
  from .context import ToolContext
@@ -0,0 +1,36 @@
1
+ import typing as ta
2
+
3
+ from ...content.content import Content
4
+ from ...content.transform.materialize import ContentMaterializer
5
+ from ...content.transform.materialize import DefaultContentMaterializer
6
+ from .context import ToolContext
7
+ from .errors import ToolExecutionError
8
+ from .executors import ToolExecutor
9
+
10
+
11
+ ##
12
+
13
+
14
+ class ErrorHandlingToolExecutor(ToolExecutor):
15
+ def __init__(
16
+ self,
17
+ *,
18
+ wrapped: ToolExecutor,
19
+ content_materializer: ContentMaterializer = DefaultContentMaterializer(),
20
+ ) -> None:
21
+ super().__init__()
22
+
23
+ self._wrapped = wrapped
24
+ self._content_materializer = content_materializer
25
+
26
+ async def execute_tool(
27
+ self,
28
+ ctx: ToolContext,
29
+ name: str,
30
+ args: ta.Mapping[str, ta.Any],
31
+ ) -> Content:
32
+ try:
33
+ return await self._wrapped.execute_tool(ctx, name, args)
34
+
35
+ except ToolExecutionError as txe:
36
+ return self._content_materializer.apply(txe.content)
@@ -2,7 +2,7 @@ import abc
2
2
 
3
3
  from omlish import lang
4
4
 
5
- from ...content.materialize import CanContent
5
+ from ...content.content import Content
6
6
 
7
7
 
8
8
  ##
@@ -11,5 +11,5 @@ from ...content.materialize import CanContent
11
11
  class ToolExecutionError(Exception, lang.Abstract):
12
12
  @property
13
13
  @abc.abstractmethod
14
- def content(self) -> CanContent:
14
+ def content(self) -> Content:
15
15
  raise NotImplementedError
@@ -8,7 +8,7 @@ import typing as ta
8
8
  from omlish import dataclasses as dc
9
9
  from omlish import lang
10
10
 
11
- from ...content.types import Content
11
+ from ...content.content import Content
12
12
  from ..fns import ToolFn
13
13
  from ..fns import execute_tool_fn
14
14
  from .context import ToolContext
@@ -10,8 +10,8 @@ from omlish import lang
10
10
  from omlish import marshal as msh
11
11
  from omlish import reflect as rfl
12
12
 
13
+ from ..content.content import Content
13
14
  from ..content.json import JsonContent
14
- from ..content.types import Content
15
15
 
16
16
 
17
17
  D = ta.TypeVar('D')
@@ -4,8 +4,8 @@ TODO:
4
4
  """
5
5
  from omlish import check
6
6
 
7
- from ..content.prepare import ContentStrPreparer
8
- from ..content.prepare import default_content_str_preparer
7
+ from ..content.transform.prepare import ContentStrPreparer
8
+ from ..content.transform.prepare import default_content_str_preparer
9
9
  from .types import EnumToolDtype
10
10
  from .types import MappingToolDtype
11
11
  from .types import NullableToolDtype