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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. ommlds/.omlish-manifests.json +332 -35
  2. ommlds/__about__.py +15 -9
  3. ommlds/_hacks/__init__.py +4 -0
  4. ommlds/_hacks/funcs.py +110 -0
  5. ommlds/_hacks/names.py +158 -0
  6. ommlds/_hacks/params.py +73 -0
  7. ommlds/_hacks/patches.py +0 -3
  8. ommlds/backends/anthropic/protocol/_marshal.py +2 -2
  9. ommlds/backends/anthropic/protocol/sse/_marshal.py +1 -1
  10. ommlds/backends/anthropic/protocol/sse/assemble.py +23 -7
  11. ommlds/backends/anthropic/protocol/sse/events.py +13 -0
  12. ommlds/backends/anthropic/protocol/types.py +30 -9
  13. ommlds/backends/google/protocol/__init__.py +3 -0
  14. ommlds/backends/google/protocol/_marshal.py +16 -0
  15. ommlds/backends/google/protocol/types.py +626 -0
  16. ommlds/backends/groq/_marshal.py +23 -0
  17. ommlds/backends/groq/protocol.py +249 -0
  18. ommlds/backends/mlx/generation.py +1 -1
  19. ommlds/backends/mlx/loading.py +58 -1
  20. ommlds/backends/ollama/__init__.py +0 -0
  21. ommlds/backends/ollama/protocol.py +170 -0
  22. ommlds/backends/openai/protocol/__init__.py +9 -28
  23. ommlds/backends/openai/protocol/_common.py +18 -0
  24. ommlds/backends/openai/protocol/_marshal.py +27 -0
  25. ommlds/backends/openai/protocol/chatcompletion/chunk.py +58 -31
  26. ommlds/backends/openai/protocol/chatcompletion/contentpart.py +49 -44
  27. ommlds/backends/openai/protocol/chatcompletion/message.py +55 -43
  28. ommlds/backends/openai/protocol/chatcompletion/request.py +114 -66
  29. ommlds/backends/openai/protocol/chatcompletion/response.py +71 -45
  30. ommlds/backends/openai/protocol/chatcompletion/responseformat.py +27 -20
  31. ommlds/backends/openai/protocol/chatcompletion/tokenlogprob.py +16 -7
  32. ommlds/backends/openai/protocol/completionusage.py +24 -15
  33. ommlds/backends/tavily/__init__.py +0 -0
  34. ommlds/backends/tavily/protocol.py +301 -0
  35. ommlds/backends/tinygrad/models/llama3/__init__.py +22 -14
  36. ommlds/backends/transformers/__init__.py +0 -0
  37. ommlds/backends/transformers/filecache.py +109 -0
  38. ommlds/backends/transformers/streamers.py +73 -0
  39. ommlds/cli/asyncs.py +30 -0
  40. ommlds/cli/backends/catalog.py +93 -0
  41. ommlds/cli/backends/configs.py +9 -0
  42. ommlds/cli/backends/inject.py +31 -36
  43. ommlds/cli/backends/injection.py +16 -0
  44. ommlds/cli/backends/types.py +46 -0
  45. ommlds/cli/content/__init__.py +0 -0
  46. ommlds/cli/content/messages.py +34 -0
  47. ommlds/cli/content/strings.py +42 -0
  48. ommlds/cli/inject.py +15 -32
  49. ommlds/cli/inputs/__init__.py +0 -0
  50. ommlds/cli/inputs/asyncs.py +32 -0
  51. ommlds/cli/inputs/sync.py +75 -0
  52. ommlds/cli/main.py +270 -110
  53. ommlds/cli/rendering/__init__.py +0 -0
  54. ommlds/cli/rendering/configs.py +9 -0
  55. ommlds/cli/rendering/inject.py +31 -0
  56. ommlds/cli/rendering/markdown.py +52 -0
  57. ommlds/cli/rendering/raw.py +73 -0
  58. ommlds/cli/rendering/types.py +21 -0
  59. ommlds/cli/secrets.py +21 -0
  60. ommlds/cli/sessions/base.py +1 -1
  61. ommlds/cli/sessions/chat/chat/__init__.py +0 -0
  62. ommlds/cli/sessions/chat/chat/ai/__init__.py +0 -0
  63. ommlds/cli/sessions/chat/chat/ai/configs.py +11 -0
  64. ommlds/cli/sessions/chat/chat/ai/inject.py +74 -0
  65. ommlds/cli/sessions/chat/chat/ai/injection.py +14 -0
  66. ommlds/cli/sessions/chat/chat/ai/rendering.py +70 -0
  67. ommlds/cli/sessions/chat/chat/ai/services.py +79 -0
  68. ommlds/cli/sessions/chat/chat/ai/tools.py +44 -0
  69. ommlds/cli/sessions/chat/chat/ai/types.py +28 -0
  70. ommlds/cli/sessions/chat/chat/state/__init__.py +0 -0
  71. ommlds/cli/sessions/chat/chat/state/configs.py +11 -0
  72. ommlds/cli/sessions/chat/chat/state/inject.py +36 -0
  73. ommlds/cli/sessions/chat/chat/state/inmemory.py +33 -0
  74. ommlds/cli/sessions/chat/chat/state/storage.py +52 -0
  75. ommlds/cli/sessions/chat/chat/state/types.py +38 -0
  76. ommlds/cli/sessions/chat/chat/user/__init__.py +0 -0
  77. ommlds/cli/sessions/chat/chat/user/configs.py +17 -0
  78. ommlds/cli/sessions/chat/chat/user/inject.py +62 -0
  79. ommlds/cli/sessions/chat/chat/user/interactive.py +31 -0
  80. ommlds/cli/sessions/chat/chat/user/oneshot.py +25 -0
  81. ommlds/cli/sessions/chat/chat/user/types.py +15 -0
  82. ommlds/cli/sessions/chat/configs.py +27 -0
  83. ommlds/cli/sessions/chat/driver.py +43 -0
  84. ommlds/cli/sessions/chat/inject.py +33 -65
  85. ommlds/cli/sessions/chat/phases/__init__.py +0 -0
  86. ommlds/cli/sessions/chat/phases/inject.py +27 -0
  87. ommlds/cli/sessions/chat/phases/injection.py +14 -0
  88. ommlds/cli/sessions/chat/phases/manager.py +29 -0
  89. ommlds/cli/sessions/chat/phases/types.py +29 -0
  90. ommlds/cli/sessions/chat/session.py +27 -0
  91. ommlds/cli/sessions/chat/tools/__init__.py +0 -0
  92. ommlds/cli/sessions/chat/tools/configs.py +22 -0
  93. ommlds/cli/sessions/chat/tools/confirmation.py +46 -0
  94. ommlds/cli/sessions/chat/tools/execution.py +66 -0
  95. ommlds/cli/sessions/chat/tools/fs/__init__.py +0 -0
  96. ommlds/cli/sessions/chat/tools/fs/configs.py +12 -0
  97. ommlds/cli/sessions/chat/tools/fs/inject.py +35 -0
  98. ommlds/cli/sessions/chat/tools/inject.py +88 -0
  99. ommlds/cli/sessions/chat/tools/injection.py +44 -0
  100. ommlds/cli/sessions/chat/tools/rendering.py +58 -0
  101. ommlds/cli/sessions/chat/tools/todo/__init__.py +0 -0
  102. ommlds/cli/sessions/chat/tools/todo/configs.py +12 -0
  103. ommlds/cli/sessions/chat/tools/todo/inject.py +31 -0
  104. ommlds/cli/sessions/chat/tools/weather/__init__.py +0 -0
  105. ommlds/cli/sessions/chat/tools/weather/configs.py +12 -0
  106. ommlds/cli/sessions/chat/tools/weather/inject.py +22 -0
  107. ommlds/cli/{tools/weather.py → sessions/chat/tools/weather/tools.py} +1 -1
  108. ommlds/cli/sessions/completion/configs.py +21 -0
  109. ommlds/cli/sessions/completion/inject.py +42 -0
  110. ommlds/cli/sessions/completion/session.py +35 -0
  111. ommlds/cli/sessions/embedding/configs.py +21 -0
  112. ommlds/cli/sessions/embedding/inject.py +42 -0
  113. ommlds/cli/sessions/embedding/session.py +33 -0
  114. ommlds/cli/sessions/inject.py +28 -11
  115. ommlds/cli/state/__init__.py +0 -0
  116. ommlds/cli/state/inject.py +28 -0
  117. ommlds/cli/{state.py → state/storage.py} +41 -24
  118. ommlds/minichain/__init__.py +84 -24
  119. ommlds/minichain/_marshal.py +49 -9
  120. ommlds/minichain/_typedvalues.py +2 -4
  121. ommlds/minichain/backends/catalogs/base.py +20 -1
  122. ommlds/minichain/backends/catalogs/simple.py +2 -2
  123. ommlds/minichain/backends/catalogs/strings.py +10 -8
  124. ommlds/minichain/backends/impls/anthropic/chat.py +65 -27
  125. ommlds/minichain/backends/impls/anthropic/names.py +10 -8
  126. ommlds/minichain/backends/impls/anthropic/protocol.py +109 -0
  127. ommlds/minichain/backends/impls/anthropic/stream.py +111 -43
  128. ommlds/minichain/backends/impls/duckduckgo/search.py +1 -1
  129. ommlds/minichain/backends/impls/dummy/__init__.py +0 -0
  130. ommlds/minichain/backends/impls/dummy/chat.py +69 -0
  131. ommlds/minichain/backends/impls/google/chat.py +114 -22
  132. ommlds/minichain/backends/impls/google/search.py +7 -2
  133. ommlds/minichain/backends/impls/google/stream.py +219 -0
  134. ommlds/minichain/backends/impls/google/tools.py +149 -0
  135. ommlds/minichain/backends/impls/groq/__init__.py +0 -0
  136. ommlds/minichain/backends/impls/groq/chat.py +75 -0
  137. ommlds/minichain/backends/impls/groq/names.py +48 -0
  138. ommlds/minichain/backends/impls/groq/protocol.py +143 -0
  139. ommlds/minichain/backends/impls/groq/stream.py +125 -0
  140. ommlds/minichain/backends/impls/llamacpp/chat.py +33 -18
  141. ommlds/minichain/backends/impls/llamacpp/completion.py +1 -1
  142. ommlds/minichain/backends/impls/llamacpp/format.py +4 -2
  143. ommlds/minichain/backends/impls/llamacpp/stream.py +37 -20
  144. ommlds/minichain/backends/impls/mistral.py +20 -5
  145. ommlds/minichain/backends/impls/mlx/chat.py +96 -22
  146. ommlds/minichain/backends/impls/ollama/__init__.py +0 -0
  147. ommlds/minichain/backends/impls/ollama/chat.py +199 -0
  148. ommlds/minichain/backends/impls/openai/chat.py +18 -8
  149. ommlds/minichain/backends/impls/openai/completion.py +10 -3
  150. ommlds/minichain/backends/impls/openai/embedding.py +10 -3
  151. ommlds/minichain/backends/impls/openai/format.py +131 -106
  152. ommlds/minichain/backends/impls/openai/names.py +31 -5
  153. ommlds/minichain/backends/impls/openai/stream.py +43 -25
  154. ommlds/minichain/backends/impls/tavily.py +66 -0
  155. ommlds/minichain/backends/impls/tinygrad/chat.py +23 -16
  156. ommlds/minichain/backends/impls/transformers/sentence.py +1 -1
  157. ommlds/minichain/backends/impls/transformers/tokens.py +1 -1
  158. ommlds/minichain/backends/impls/transformers/transformers.py +155 -34
  159. ommlds/minichain/backends/strings/parsing.py +1 -1
  160. ommlds/minichain/backends/strings/resolving.py +4 -1
  161. ommlds/minichain/chat/_marshal.py +16 -9
  162. ommlds/minichain/chat/choices/adapters.py +4 -4
  163. ommlds/minichain/chat/choices/services.py +1 -1
  164. ommlds/minichain/chat/choices/stream/__init__.py +0 -0
  165. ommlds/minichain/chat/choices/stream/adapters.py +35 -0
  166. ommlds/minichain/chat/choices/stream/joining.py +31 -0
  167. ommlds/minichain/chat/choices/stream/services.py +45 -0
  168. ommlds/minichain/chat/choices/stream/types.py +43 -0
  169. ommlds/minichain/chat/choices/types.py +2 -2
  170. ommlds/minichain/chat/history.py +3 -3
  171. ommlds/minichain/chat/messages.py +55 -19
  172. ommlds/minichain/chat/services.py +3 -3
  173. ommlds/minichain/chat/stream/_marshal.py +16 -0
  174. ommlds/minichain/chat/stream/joining.py +85 -0
  175. ommlds/minichain/chat/stream/services.py +15 -21
  176. ommlds/minichain/chat/stream/types.py +32 -19
  177. ommlds/minichain/chat/tools/execution.py +8 -7
  178. ommlds/minichain/chat/tools/ids.py +9 -15
  179. ommlds/minichain/chat/tools/parsing.py +17 -26
  180. ommlds/minichain/chat/transforms/base.py +29 -38
  181. ommlds/minichain/chat/transforms/metadata.py +30 -4
  182. ommlds/minichain/chat/transforms/services.py +9 -11
  183. ommlds/minichain/content/_marshal.py +44 -20
  184. ommlds/minichain/content/json.py +13 -0
  185. ommlds/minichain/content/materialize.py +14 -21
  186. ommlds/minichain/content/prepare.py +4 -0
  187. ommlds/minichain/content/transforms/interleave.py +1 -1
  188. ommlds/minichain/content/transforms/squeeze.py +1 -1
  189. ommlds/minichain/content/transforms/stringify.py +1 -1
  190. ommlds/minichain/json.py +20 -0
  191. ommlds/minichain/lib/code/__init__.py +0 -0
  192. ommlds/minichain/lib/code/prompts.py +6 -0
  193. ommlds/minichain/lib/fs/binfiles.py +108 -0
  194. ommlds/minichain/lib/fs/context.py +126 -0
  195. ommlds/minichain/lib/fs/errors.py +101 -0
  196. ommlds/minichain/lib/fs/suggestions.py +36 -0
  197. ommlds/minichain/lib/fs/tools/__init__.py +0 -0
  198. ommlds/minichain/lib/fs/tools/edit.py +104 -0
  199. ommlds/minichain/lib/fs/tools/ls.py +38 -0
  200. ommlds/minichain/lib/fs/tools/read.py +115 -0
  201. ommlds/minichain/lib/fs/tools/recursivels/__init__.py +0 -0
  202. ommlds/minichain/lib/fs/tools/recursivels/execution.py +40 -0
  203. ommlds/minichain/lib/todo/__init__.py +0 -0
  204. ommlds/minichain/lib/todo/context.py +54 -0
  205. ommlds/minichain/lib/todo/tools/__init__.py +0 -0
  206. ommlds/minichain/lib/todo/tools/read.py +44 -0
  207. ommlds/minichain/lib/todo/tools/write.py +335 -0
  208. ommlds/minichain/lib/todo/types.py +60 -0
  209. ommlds/minichain/llms/_marshal.py +25 -17
  210. ommlds/minichain/llms/types.py +4 -0
  211. ommlds/minichain/registries/globals.py +18 -4
  212. ommlds/minichain/resources.py +66 -43
  213. ommlds/minichain/search.py +1 -1
  214. ommlds/minichain/services/_marshal.py +46 -39
  215. ommlds/minichain/services/facades.py +3 -3
  216. ommlds/minichain/services/services.py +1 -1
  217. ommlds/minichain/standard.py +8 -0
  218. ommlds/minichain/stream/services.py +152 -38
  219. ommlds/minichain/stream/wrap.py +22 -24
  220. ommlds/minichain/tools/_marshal.py +1 -1
  221. ommlds/minichain/tools/execution/catalog.py +2 -1
  222. ommlds/minichain/tools/execution/context.py +34 -14
  223. ommlds/minichain/tools/execution/errors.py +15 -0
  224. ommlds/minichain/tools/execution/executors.py +8 -3
  225. ommlds/minichain/tools/execution/reflect.py +40 -5
  226. ommlds/minichain/tools/fns.py +46 -9
  227. ommlds/minichain/tools/jsonschema.py +14 -5
  228. ommlds/minichain/tools/reflect.py +54 -18
  229. ommlds/minichain/tools/types.py +33 -1
  230. ommlds/minichain/utils.py +27 -0
  231. ommlds/minichain/vectors/_marshal.py +11 -10
  232. ommlds/nanochat/LICENSE +21 -0
  233. ommlds/nanochat/__init__.py +0 -0
  234. ommlds/nanochat/rustbpe/LICENSE +21 -0
  235. ommlds/nanochat/tokenizers.py +406 -0
  236. ommlds/server/server.py +3 -3
  237. ommlds/specs/__init__.py +0 -0
  238. ommlds/specs/mcp/__init__.py +0 -0
  239. ommlds/specs/mcp/_marshal.py +23 -0
  240. ommlds/specs/mcp/protocol.py +266 -0
  241. ommlds/tools/git.py +27 -10
  242. ommlds/tools/ocr.py +8 -9
  243. ommlds/wiki/analyze.py +2 -2
  244. ommlds/wiki/text/mfh.py +1 -5
  245. ommlds/wiki/text/wtp.py +1 -3
  246. ommlds/wiki/utils/xml.py +5 -5
  247. {ommlds-0.0.0.dev436.dist-info → ommlds-0.0.0.dev480.dist-info}/METADATA +24 -21
  248. ommlds-0.0.0.dev480.dist-info/RECORD +427 -0
  249. ommlds/cli/backends/standard.py +0 -20
  250. ommlds/cli/sessions/chat/base.py +0 -42
  251. ommlds/cli/sessions/chat/interactive.py +0 -73
  252. ommlds/cli/sessions/chat/printing.py +0 -96
  253. ommlds/cli/sessions/chat/prompt.py +0 -143
  254. ommlds/cli/sessions/chat/state.py +0 -109
  255. ommlds/cli/sessions/chat/tools.py +0 -91
  256. ommlds/cli/sessions/completion/completion.py +0 -44
  257. ommlds/cli/sessions/embedding/embedding.py +0 -42
  258. ommlds/cli/tools/config.py +0 -13
  259. ommlds/cli/tools/inject.py +0 -64
  260. ommlds/minichain/chat/stream/adapters.py +0 -69
  261. ommlds/minichain/lib/fs/ls/execution.py +0 -32
  262. ommlds-0.0.0.dev436.dist-info/RECORD +0 -303
  263. /ommlds/{cli/tools → backends/google}/__init__.py +0 -0
  264. /ommlds/{minichain/lib/fs/ls → backends/groq}/__init__.py +0 -0
  265. /ommlds/{huggingface.py → backends/huggingface.py} +0 -0
  266. /ommlds/minichain/lib/fs/{ls → tools/recursivels}/rendering.py +0 -0
  267. /ommlds/minichain/lib/fs/{ls → tools/recursivels}/running.py +0 -0
  268. {ommlds-0.0.0.dev436.dist-info → ommlds-0.0.0.dev480.dist-info}/WHEEL +0 -0
  269. {ommlds-0.0.0.dev436.dist-info → ommlds-0.0.0.dev480.dist-info}/entry_points.txt +0 -0
  270. {ommlds-0.0.0.dev436.dist-info → ommlds-0.0.0.dev480.dist-info}/licenses/LICENSE +0 -0
  271. {ommlds-0.0.0.dev436.dist-info → ommlds-0.0.0.dev480.dist-info}/top_level.txt +0 -0
ommlds/_hacks/funcs.py ADDED
@@ -0,0 +1,110 @@
1
+ import dataclasses as dc
2
+ import linecache
3
+ import textwrap
4
+ import threading
5
+ import types
6
+ import typing as ta
7
+ import uuid
8
+ import warnings
9
+
10
+ from omlish import check
11
+ from omlish import lang
12
+
13
+ from .names import NamespaceBuilder
14
+ from .params import render_param_spec_call
15
+ from .params import render_param_spec_def
16
+
17
+
18
+ ##
19
+
20
+
21
+ @dc.dataclass()
22
+ class _ReservedFilenameEntry:
23
+ unique_id: str
24
+ seq: int = 0
25
+
26
+
27
+ _RESERVED_FILENAME_UUID_TLS = threading.local()
28
+
29
+
30
+ def reserve_linecache_filename(prefix: str) -> str:
31
+ try:
32
+ e = _RESERVED_FILENAME_UUID_TLS.unique_id
33
+ except AttributeError:
34
+ e = _RESERVED_FILENAME_UUID_TLS.unique_id = _ReservedFilenameEntry(str(uuid.uuid4()))
35
+
36
+ while True:
37
+ unique_filename = f'<generated:{prefix}:{e.seq}>'
38
+ cache_line = (1, None, (e.unique_id,), unique_filename)
39
+ e.seq += 1
40
+ if linecache.cache.setdefault(unique_filename, cache_line) == cache_line: # type: ignore
41
+ return unique_filename
42
+
43
+
44
+ ##
45
+
46
+
47
+ def create_function(
48
+ name: str,
49
+ params: lang.CanParamSpec,
50
+ body: str,
51
+ *,
52
+ globals: ta.Mapping[str, ta.Any] | None = None, # noqa
53
+ locals: ta.Mapping[str, ta.Any] | None = None, # noqa
54
+ indent: str = ' ',
55
+ ) -> types.FunctionType:
56
+ params = lang.ParamSpec.of(params)
57
+ check.isinstance(body, str)
58
+ locals = dict(locals or {}) # noqa
59
+
60
+ nsb = NamespaceBuilder(reserved_names=set(locals) | set(globals or []))
61
+ sig = render_param_spec_def(params, nsb)
62
+ for k, v in nsb.items():
63
+ check.not_in(k, locals)
64
+ locals[k] = v
65
+
66
+ body_txt = '\n'.join([
67
+ f'def {name}{sig}:',
68
+ textwrap.indent(textwrap.dedent(body.strip()), indent),
69
+ ])
70
+
71
+ exec_txt = '\n'.join([
72
+ f'def __create_fn__({", ".join(locals.keys())}):',
73
+ textwrap.indent(body_txt, indent),
74
+ f'{indent}return {name}',
75
+ ])
76
+
77
+ ns: dict = {}
78
+ filename = reserve_linecache_filename(name)
79
+ bytecode = compile(exec_txt, filename, 'exec')
80
+ eval(bytecode, globals or {}, ns) # type: ignore # noqa
81
+
82
+ fn = ns['__create_fn__'](**locals)
83
+ fn.__source__ = body_txt
84
+ linecache.cache[filename] = (len(exec_txt), None, exec_txt.splitlines(True), filename)
85
+ return fn
86
+
87
+
88
+ ##
89
+
90
+
91
+ def create_detour(
92
+ params: lang.CanParamSpec,
93
+ target: ta.Callable,
94
+ *,
95
+ as_kwargs: bool = False,
96
+ ) -> types.CodeType:
97
+ params = lang.ParamSpec.of(params)
98
+ check.callable(target)
99
+
100
+ with warnings.catch_warnings():
101
+ warnings.filterwarnings('ignore', category=SyntaxWarning)
102
+
103
+ gfn = create_function(
104
+ '_',
105
+ params,
106
+ f'return 1{render_param_spec_call(params, as_kwargs=as_kwargs)}',
107
+ )
108
+
109
+ check.state(gfn.__code__.co_consts[:2] == (None, 1))
110
+ return gfn.__code__.replace(co_consts=(None, target, *gfn.__code__.co_consts[2:]))
ommlds/_hacks/names.py ADDED
@@ -0,0 +1,158 @@
1
+ """
2
+ TODO:
3
+ - releaseable names
4
+ """
5
+ import string
6
+ import typing as ta
7
+
8
+ from omlish import check
9
+ from omlish import collections as col
10
+
11
+
12
+ ##
13
+
14
+
15
+ class NameGenerator(ta.Protocol):
16
+ def __call__(self, prefix: str = '') -> str: ...
17
+
18
+
19
+ #
20
+
21
+
22
+ class NameGeneratorImpl:
23
+ DEFAULT_PREFIX: ta.ClassVar[str] = '_'
24
+
25
+ def __init__(
26
+ self,
27
+ *,
28
+ reserved_names: ta.Iterable[str] | None = None,
29
+ global_prefix: str | None = None,
30
+ use_global_prefix_if_present: bool = False,
31
+ add_global_prefix_before_number: bool = False,
32
+ ) -> None:
33
+ super().__init__()
34
+
35
+ check.arg(not isinstance(reserved_names, str))
36
+ self._reserved_names = {check.isinstance(n, str) for n in (reserved_names or [])}
37
+ self._global_prefix = global_prefix if global_prefix is not None else self.DEFAULT_PREFIX
38
+ self._use_global_prefix_if_present = bool(use_global_prefix_if_present)
39
+ self._add_global_prefix_before_number = bool(add_global_prefix_before_number)
40
+
41
+ self._name_counts: dict[str, int] = {}
42
+
43
+ def __call__(self, prefix: str = '') -> str:
44
+ if self._use_global_prefix_if_present and prefix.startswith(self._global_prefix):
45
+ base_name = prefix
46
+ else:
47
+ base_name = self._global_prefix + prefix
48
+
49
+ base_count = -1
50
+ if base_name[-1] in string.digits:
51
+ i = len(base_name) - 2
52
+ while i >= 0 and base_name[i] in string.digits:
53
+ i -= 1
54
+ i += 1
55
+ base_count = int(base_name[i:])
56
+ base_name = base_name[:i]
57
+
58
+ if self._add_global_prefix_before_number:
59
+ if not (self._use_global_prefix_if_present and base_name.endswith(self._global_prefix)):
60
+ base_name += self._global_prefix
61
+
62
+ if base_count >= 0:
63
+ count = self._name_counts.setdefault(base_name, 0)
64
+ if base_count > count:
65
+ self._name_counts[base_name] = base_count
66
+
67
+ while True:
68
+ count = self._name_counts.get(base_name, 0)
69
+ self._name_counts[base_name] = count + 1
70
+ name = base_name + str(count)
71
+ if name not in self._reserved_names:
72
+ return name
73
+
74
+
75
+ name_generator = NameGeneratorImpl
76
+
77
+
78
+ ##
79
+
80
+
81
+ class NamespaceBuilder(ta.Mapping[str, ta.Any]):
82
+ def __init__(
83
+ self,
84
+ *,
85
+ reserved_names: ta.Iterable[str] | None = None,
86
+ name_generator: NameGenerator | None = None, # noqa
87
+ ) -> None:
88
+ super().__init__()
89
+
90
+ self._reserved_names = {
91
+ check.isinstance(n, str)
92
+ for n in (check.not_isinstance(reserved_names, str) or [])
93
+ }
94
+ self._name_generator = check.callable(name_generator) if name_generator is not None else \
95
+ NameGeneratorImpl(reserved_names=self._reserved_names, use_global_prefix_if_present=True)
96
+
97
+ self._dct: ta.MutableMapping[str, ta.Any] = {}
98
+ self._dedupe_dct: ta.MutableMapping[ta.Any, str] = col.IdentityKeyDict()
99
+
100
+ @property
101
+ def reserved_names(self) -> ta.AbstractSet[str]:
102
+ return self._reserved_names
103
+
104
+ @property
105
+ def name_generator(self) -> NameGenerator:
106
+ return self._name_generator
107
+
108
+ def __getitem__(self, k: str) -> ta.Any:
109
+ return self._dct[k]
110
+
111
+ def __len__(self):
112
+ return len(self._dct)
113
+
114
+ def __iter__(self) -> ta.Iterator[str]:
115
+ return iter(self._dct)
116
+
117
+ def items(self) -> ta.ItemsView[str, ta.Any]:
118
+ return self._dct.items()
119
+
120
+ def put(
121
+ self,
122
+ value: ta.Any,
123
+ name: str | None = None,
124
+ *,
125
+ exact: bool = False,
126
+ dedupe: bool = False,
127
+ ) -> str:
128
+ check.arg(not (name is None and exact))
129
+ if name is not None:
130
+ check.isinstance(name, str)
131
+
132
+ if dedupe:
133
+ try:
134
+ return self._dedupe_dct[value]
135
+ except KeyError:
136
+ pass
137
+
138
+ if name is not None:
139
+ if name not in self._reserved_names:
140
+ try:
141
+ existing = self._dct[name]
142
+ except KeyError:
143
+ self._dct[name] = value
144
+ if dedupe:
145
+ self._dedupe_dct[value] = name
146
+ return name
147
+ else:
148
+ if existing is value:
149
+ return name
150
+ if exact:
151
+ raise KeyError(name)
152
+
153
+ gen_name = self._name_generator(name or '')
154
+ check.not_in(gen_name, self._dct)
155
+ self._dct[gen_name] = value
156
+ if dedupe:
157
+ self._dedupe_dct[value] = gen_name
158
+ return gen_name
@@ -0,0 +1,73 @@
1
+ import typing as ta
2
+
3
+ from omlish import lang
4
+
5
+ from .names import NamespaceBuilder
6
+
7
+
8
+ ##
9
+
10
+
11
+ def render_param_spec_call(
12
+ params: lang.ParamSpec,
13
+ *,
14
+ as_kwargs: bool = False,
15
+ ) -> str:
16
+ src = ['(']
17
+
18
+ for i, p in enumerate(params):
19
+ if isinstance(p, lang.ParamSeparator):
20
+ continue
21
+
22
+ if i:
23
+ src.append(', ')
24
+
25
+ if as_kwargs:
26
+ if isinstance(p, lang.Param):
27
+ src.append(f'{p.name}={p.name}')
28
+ else:
29
+ raise TypeError(p)
30
+
31
+ else:
32
+ if isinstance(p, lang.ArgsParam):
33
+ src.append(f'*{p.name}')
34
+ elif isinstance(p, lang.KwargsParam):
35
+ src.append(f'**{p.name}')
36
+ elif isinstance(p, lang.PosOnlyParam):
37
+ src.append(p.name)
38
+ elif isinstance(p, lang.KwOnlyParam):
39
+ src.append(f'{p.name}={p.name}')
40
+ elif isinstance(p, lang.ValParam):
41
+ src.append(p.name)
42
+ else:
43
+ raise TypeError(p)
44
+
45
+ src.append(')')
46
+
47
+ return ''.join(src)
48
+
49
+
50
+ def render_param_spec_def(
51
+ params: lang.ParamSpec,
52
+ nsb: NamespaceBuilder,
53
+ *,
54
+ return_ann: lang.Maybe[ta.Any] = lang.empty(),
55
+ ) -> str:
56
+ src = ['(']
57
+
58
+ for i, p in enumerate(params):
59
+ if i:
60
+ src.append(', ')
61
+
62
+ src.append(lang.param_render(
63
+ p,
64
+ render_annotation=lambda ann: nsb.put(ann, f'ann_{p.name}'), # noqa
65
+ render_default=lambda dfl: nsb.put(dfl, f'dfl_{p.name}'), # noqa
66
+ ))
67
+
68
+ src.append(')')
69
+
70
+ if return_ann.present:
71
+ src.append(f' -> {nsb.put(return_ann.must(), "ann_return")}')
72
+
73
+ return ''.join(src)
ommlds/_hacks/patches.py CHANGED
@@ -1,7 +1,4 @@
1
1
  """
2
- Currently, and ideally, the only thing this codebase will ever interact with requiring these kinds of awful hacks is ML
3
- code - thus these 'helpers' are kept here, not in the core library.
4
-
5
2
  TODO:
6
3
  - patch lock
7
4
  - thread / context local gating
@@ -8,7 +8,7 @@ from .types import Content
8
8
 
9
9
 
10
10
  @lang.static_init
11
- def _install_standard_marshalling() -> None:
11
+ def _install_standard_marshaling() -> None:
12
12
  for root_cls in [
13
13
  Content,
14
14
  Content.CacheControl,
@@ -17,7 +17,7 @@ def _install_standard_marshalling() -> None:
17
17
  msh.polymorphism_from_subclasses(
18
18
  root_cls,
19
19
  naming=msh.Naming.SNAKE,
20
- strip_suffix='auto',
20
+ strip_suffix=msh.AutoStripSuffix,
21
21
  ),
22
22
  msh.FieldTypeTagging('type'),
23
23
  ))
@@ -8,7 +8,7 @@ from .events import AnthropicSseDecoderEvents
8
8
 
9
9
 
10
10
  @lang.static_init
11
- def _install_standard_marshalling() -> None:
11
+ def _install_standard_marshaling() -> None:
12
12
  for root_cls in [
13
13
  AnthropicSseDecoderEvents.Event,
14
14
  AnthropicSseDecoderEvents.ContentBlockStart.ContentBlock,
@@ -63,9 +63,10 @@ class AnthropicSseMessageAssembler(
63
63
  while True:
64
64
  ae: ta.Any = check.not_none((yield from self._next_event()))
65
65
  if isinstance(ae, AnthropicSseDecoderEvents.ContentBlockStart):
66
- check.equal(ae.index, len(content))
66
+ # check.equal(ae.index, len(content))
67
67
  c = yield from self._do_content_block(ae)
68
- content.append(check.isinstance(c, Content))
68
+ if c is not None:
69
+ content.append(check.isinstance(c, Content))
69
70
  elif isinstance(ae, AnthropicSseDecoderEvents.MessageDelta):
70
71
  for k in ('stop_reason', 'stop_sequence'):
71
72
  if (v := getattr(ae.delta, k)) is not None:
@@ -76,7 +77,7 @@ class AnthropicSseMessageAssembler(
76
77
  elif isinstance(ae, AnthropicSseDecoderEvents.MessageStop):
77
78
  yield [Message(
78
79
  id=ms.message.id,
79
- role=ms.message.role,
80
+ role=ms.message.role, # type: ignore[arg-type]
80
81
  model=ms.message.model,
81
82
  content=content,
82
83
  stop_reason=dct['stop_reason'],
@@ -92,6 +93,8 @@ class AnthropicSseMessageAssembler(
92
93
  return (yield from self._do_text_content_block(cbs))
93
94
  elif isinstance(cbs.content_block, AnthropicSseDecoderEvents.ContentBlockStart.ToolUse):
94
95
  return (yield from self._do_tool_use_content_block(cbs))
96
+ elif isinstance(cbs.content_block, AnthropicSseDecoderEvents.ContentBlockStart.Thinking):
97
+ return (yield from self._do_thinking_content_block(cbs))
95
98
  else:
96
99
  raise TypeError(cbs.content_block)
97
100
 
@@ -101,11 +104,11 @@ class AnthropicSseMessageAssembler(
101
104
  while True:
102
105
  ae: ta.Any = check.not_none((yield from self._next_event()))
103
106
  if isinstance(ae, AnthropicSseDecoderEvents.ContentBlockDelta):
104
- check.equal(ae.index, cbs.index)
107
+ # check.equal(ae.index, cbs.index)
105
108
  cdc = check.isinstance(ae.delta, AnthropicSseDecoderEvents.ContentBlockDelta.TextDelta)
106
109
  parts.append(cdc.text)
107
110
  elif isinstance(ae, AnthropicSseDecoderEvents.ContentBlockStop):
108
- check.equal(ae.index, cbs.index)
111
+ # check.equal(ae.index, cbs.index)
109
112
  return Text(''.join(parts))
110
113
  else:
111
114
  raise TypeError(ae)
@@ -119,11 +122,11 @@ class AnthropicSseMessageAssembler(
119
122
  while True:
120
123
  ae: ta.Any = check.not_none((yield from self._next_event()))
121
124
  if isinstance(ae, AnthropicSseDecoderEvents.ContentBlockDelta):
122
- check.equal(ae.index, cbs.index)
125
+ # check.equal(ae.index, cbs.index)
123
126
  cdc = check.isinstance(ae.delta, AnthropicSseDecoderEvents.ContentBlockDelta.InputJsonDelta)
124
127
  json_parts.append(cdc.partial_json)
125
128
  elif isinstance(ae, AnthropicSseDecoderEvents.ContentBlockStop):
126
- check.equal(ae.index, cbs.index)
129
+ # check.equal(ae.index, cbs.index)
127
130
  dj = ''.join(json_parts).strip()
128
131
  if dj:
129
132
  dd = check.isinstance(json.loads(dj), ta.Mapping)
@@ -138,3 +141,16 @@ class AnthropicSseMessageAssembler(
138
141
  )
139
142
  else:
140
143
  raise TypeError(ae)
144
+
145
+ def _do_thinking_content_block(self, cbs: AnthropicSseDecoderEvents.ContentBlockStart) -> ta.Any:
146
+ # csc = check.isinstance(cbs.content_block, AnthropicSseDecoderEvents.ContentBlockStart.Thinking)
147
+ while True:
148
+ ae: ta.Any = check.not_none((yield from self._next_event()))
149
+ if isinstance(ae, AnthropicSseDecoderEvents.ContentBlockDelta):
150
+ pass
151
+ elif isinstance(ae, AnthropicSseDecoderEvents.ContentBlockStop):
152
+ return None
153
+ else:
154
+ raise TypeError(ae)
155
+ return # type: ignore # noqa
156
+ yield # noqa
@@ -80,6 +80,11 @@ class AnthropicSseDecoderEvents(lang.Namespace):
80
80
  name: str
81
81
  input: ta.Any
82
82
 
83
+ @dc.dataclass(frozen=True)
84
+ class Thinking(ContentBlock):
85
+ signature: str
86
+ thinking: str
87
+
83
88
  content_block: ContentBlock
84
89
  index: int
85
90
 
@@ -96,6 +101,14 @@ class AnthropicSseDecoderEvents(lang.Namespace):
96
101
  class InputJsonDelta(Delta):
97
102
  partial_json: str
98
103
 
104
+ @dc.dataclass(frozen=True)
105
+ class ThinkingDelta(Delta):
106
+ thinking: str
107
+
108
+ @dc.dataclass(frozen=True)
109
+ class SignatureDelta(Delta):
110
+ signature: str
111
+
99
112
  delta: Delta
100
113
  index: int
101
114
 
@@ -1,3 +1,6 @@
1
+ """
2
+ https://docs.claude.com/en/api/messages
3
+ """
1
4
  import typing as ta
2
5
 
3
6
  from omlish import dataclasses as dc
@@ -8,6 +11,22 @@ from omlish import marshal as msh
8
11
  ##
9
12
 
10
13
 
14
+ def _set_class_marshal_options(cls):
15
+ msh.update_object_metadata(
16
+ cls,
17
+ field_defaults=msh.FieldMetadata(
18
+ options=msh.FieldOptions(
19
+ omit_if=lang.is_none,
20
+ ),
21
+ ),
22
+ )
23
+
24
+ return cls
25
+
26
+
27
+ ##
28
+
29
+
11
30
  class Content(lang.Abstract, lang.Sealed):
12
31
  class CacheControl(lang.Abstract, lang.Sealed):
13
32
  """https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching"""
@@ -18,7 +37,7 @@ class Content(lang.Abstract, lang.Sealed):
18
37
 
19
38
 
20
39
  @dc.dataclass(frozen=True)
21
- @msh.update_fields_metadata(['cache_control'], omit_if=lang.is_none)
40
+ @_set_class_marshal_options
22
41
  class Text(Content):
23
42
  text: str
24
43
 
@@ -28,7 +47,7 @@ class Text(Content):
28
47
 
29
48
 
30
49
  @dc.dataclass(frozen=True)
31
- @msh.update_fields_metadata(['cache_control'], omit_if=lang.is_none)
50
+ @_set_class_marshal_options
32
51
  class ToolUse(Content):
33
52
  id: str
34
53
  name: str
@@ -40,6 +59,7 @@ class ToolUse(Content):
40
59
 
41
60
 
42
61
  @dc.dataclass(frozen=True)
62
+ @_set_class_marshal_options
43
63
  class ToolResult(Content):
44
64
  tool_use_id: str
45
65
  content: str
@@ -49,7 +69,7 @@ class ToolResult(Content):
49
69
 
50
70
 
51
71
  @dc.dataclass(frozen=True, kw_only=True)
52
- @msh.update_object_metadata(field_defaults=msh.FieldMetadata(options=msh.FieldOptions(omit_if=lang.is_none)))
72
+ @_set_class_marshal_options
53
73
  class CacheCreation:
54
74
  ephemeral_5m_input_tokens: int | None = None
55
75
  ephemeral_1h_input_tokens: int | None = None
@@ -59,7 +79,7 @@ class CacheCreation:
59
79
 
60
80
 
61
81
  @dc.dataclass(frozen=True, kw_only=True)
62
- @msh.update_object_metadata(field_defaults=msh.FieldMetadata(options=msh.FieldOptions(omit_if=lang.is_none)))
82
+ @_set_class_marshal_options
63
83
  class Usage:
64
84
  input_tokens: int | None = None
65
85
  output_tokens: int | None = None
@@ -75,15 +95,15 @@ class Usage:
75
95
 
76
96
 
77
97
  @dc.dataclass(frozen=True, kw_only=True)
78
- @msh.update_object_metadata(field_defaults=msh.FieldMetadata(options=msh.FieldOptions(omit_if=lang.is_none)))
98
+ @_set_class_marshal_options
79
99
  class Message:
80
100
  id: str | None = None
81
101
 
82
- role: str | None = None
102
+ role: ta.Literal['user', 'assistant']
83
103
 
84
104
  model: str | None = None
85
105
 
86
- content: ta.Sequence[Content] | None = None
106
+ content: str | ta.Sequence[Content] | None = None
87
107
 
88
108
  stop_reason: str | None = None
89
109
  stop_sequence: str | None = None
@@ -95,6 +115,7 @@ class Message:
95
115
 
96
116
 
97
117
  @dc.dataclass(frozen=True)
118
+ @_set_class_marshal_options
98
119
  class ToolSpec:
99
120
  name: str
100
121
  description: str
@@ -105,7 +126,7 @@ class ToolSpec:
105
126
 
106
127
 
107
128
  @dc.dataclass(frozen=True)
108
- @msh.update_object_metadata(field_defaults=msh.FieldMetadata(options=msh.FieldOptions(omit_if=lang.is_none)))
129
+ @_set_class_marshal_options
109
130
  class MessagesRequest:
110
131
  model: str
111
132
 
@@ -113,7 +134,7 @@ class MessagesRequest:
113
134
 
114
135
  _: dc.KW_ONLY
115
136
 
116
- system: ta.Sequence[Content] | None = None
137
+ system: str | ta.Sequence[Content] | None = None
117
138
 
118
139
  tools: ta.Sequence[ToolSpec] | None = None
119
140
 
@@ -0,0 +1,3 @@
1
+ from omlish import marshal as _msh # noqa
2
+
3
+ _msh.register_global_module_import('._marshal', __package__)
@@ -0,0 +1,16 @@
1
+ from omlish import lang
2
+ from omlish import marshal as msh
3
+
4
+ from .types import Value
5
+
6
+
7
+ ##
8
+
9
+
10
+ @lang.static_init
11
+ def _install_standard_marshaling() -> None:
12
+ msh.install_standard_factories(
13
+ *msh.standard_polymorphism_factories(
14
+ msh.polymorphism_from_subclasses(Value),
15
+ ),
16
+ )