ommlds 0.0.0.dev496__py3-none-any.whl → 0.0.0.dev498__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.
- ommlds/.omlish-manifests.json +1 -1
- ommlds/cli/main.py +2 -2
- ommlds/cli/secrets.py +1 -1
- ommlds/minichain/__init__.py +45 -9
- ommlds/minichain/_dataclasses.py +1229 -1071
- ommlds/minichain/_typedvalues.py +11 -4
- ommlds/minichain/chat/content.py +42 -0
- ommlds/minichain/chat/messages.py +21 -14
- ommlds/minichain/chat/stream/types.py +1 -1
- ommlds/minichain/chat/templating.py +3 -3
- ommlds/minichain/chat/transforms/metadata.py +3 -3
- ommlds/minichain/content/__init__.py +10 -1
- ommlds/minichain/content/_marshal.py +30 -17
- ommlds/minichain/content/code.py +11 -2
- ommlds/minichain/content/composite.py +28 -0
- ommlds/minichain/content/{types.py → content.py} +0 -4
- ommlds/minichain/content/emphasis.py +27 -0
- ommlds/minichain/content/images.py +1 -2
- ommlds/minichain/content/json.py +1 -2
- ommlds/minichain/content/link.py +13 -0
- ommlds/minichain/content/markdown.py +12 -0
- ommlds/minichain/content/metadata.py +10 -0
- ommlds/minichain/content/namespaces.py +2 -3
- ommlds/minichain/content/placeholders.py +2 -3
- ommlds/minichain/content/quote.py +12 -3
- ommlds/minichain/content/recursive.py +12 -0
- ommlds/minichain/content/section.py +16 -4
- ommlds/minichain/content/sequence.py +13 -4
- ommlds/minichain/content/standard.py +10 -15
- ommlds/minichain/content/tag.py +12 -3
- ommlds/minichain/content/templates.py +1 -2
- ommlds/minichain/content/text.py +1 -2
- ommlds/minichain/content/transform/json.py +55 -0
- ommlds/minichain/content/transform/markdown.py +8 -0
- ommlds/minichain/content/transform/materialize.py +19 -78
- ommlds/minichain/content/transform/metadata.py +16 -0
- ommlds/minichain/content/transform/prepare.py +1 -5
- ommlds/minichain/content/transform/recursive.py +97 -0
- ommlds/minichain/content/transform/standard.py +43 -0
- ommlds/minichain/content/transform/stringify.py +1 -1
- ommlds/minichain/content/transform/strings.py +16 -7
- ommlds/minichain/content/transform/templates.py +25 -0
- ommlds/minichain/content/visitors.py +231 -0
- ommlds/minichain/metadata.py +58 -1
- ommlds/minichain/tools/execution/catalog.py +1 -1
- ommlds/minichain/tools/execution/errorhandling.py +3 -2
- ommlds/minichain/tools/execution/errors.py +1 -1
- ommlds/minichain/tools/execution/executors.py +1 -1
- ommlds/minichain/tools/fns.py +1 -1
- ommlds/minichain/tools/reflect.py +1 -1
- ommlds/minichain/tools/types.py +1 -1
- ommlds/minichain/vectors/embeddings.py +1 -1
- ommlds/tools/git.py +74 -63
- {ommlds-0.0.0.dev496.dist-info → ommlds-0.0.0.dev498.dist-info}/METADATA +4 -4
- {ommlds-0.0.0.dev496.dist-info → ommlds-0.0.0.dev498.dist-info}/RECORD +59 -49
- ommlds/minichain/content/transform/base.py +0 -63
- ommlds/minichain/content/transform/interleave.py +0 -68
- ommlds/minichain/content/transform/squeeze.py +0 -59
- {ommlds-0.0.0.dev496.dist-info → ommlds-0.0.0.dev498.dist-info}/WHEEL +0 -0
- {ommlds-0.0.0.dev496.dist-info → ommlds-0.0.0.dev498.dist-info}/entry_points.txt +0 -0
- {ommlds-0.0.0.dev496.dist-info → ommlds-0.0.0.dev498.dist-info}/licenses/LICENSE +0 -0
- {ommlds-0.0.0.dev496.dist-info → ommlds-0.0.0.dev498.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import collections.abc
|
|
2
|
+
import inspect
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
from omlish import check
|
|
6
|
+
from omlish import lang
|
|
7
|
+
|
|
8
|
+
from .code import BlockCodeContent
|
|
9
|
+
from .code import CodeContent
|
|
10
|
+
from .code import InlineCodeContent
|
|
11
|
+
from .composite import CompositeContent
|
|
12
|
+
from .content import BaseContent
|
|
13
|
+
from .content import Content
|
|
14
|
+
from .dynamic import DynamicContent
|
|
15
|
+
from .emphasis import BoldContent
|
|
16
|
+
from .emphasis import BoldItalicContent
|
|
17
|
+
from .emphasis import EmphasisContent
|
|
18
|
+
from .emphasis import ItalicContent
|
|
19
|
+
from .images import ImageContent
|
|
20
|
+
from .json import JsonContent
|
|
21
|
+
from .link import LinkContent
|
|
22
|
+
from .markdown import MarkdownContent
|
|
23
|
+
from .namespaces import NamespaceContent
|
|
24
|
+
from .placeholders import PlaceholderContent
|
|
25
|
+
from .quote import QuoteContent
|
|
26
|
+
from .recursive import RecursiveContent
|
|
27
|
+
from .section import SectionContent
|
|
28
|
+
from .sequence import BlockContent
|
|
29
|
+
from .sequence import InlineContent
|
|
30
|
+
from .sequence import ItemListContent
|
|
31
|
+
from .sequence import SequenceContent
|
|
32
|
+
from .standard import StandardContent
|
|
33
|
+
from .tag import TagContent
|
|
34
|
+
from .templates import TemplateContent
|
|
35
|
+
from .text import TextContent
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
C = ta.TypeVar('C')
|
|
39
|
+
R = ta.TypeVar('R')
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
##
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ContentVisitor(lang.Abstract, ta.Generic[C, R]):
|
|
46
|
+
_visit_method_map: ta.ClassVar[ta.Mapping[ta.Any, str]]
|
|
47
|
+
|
|
48
|
+
def visit(self, c: Content, ctx: C) -> R:
|
|
49
|
+
if isinstance(c, str):
|
|
50
|
+
return self.visit_str(c, ctx)
|
|
51
|
+
|
|
52
|
+
if isinstance(c, collections.abc.Sequence):
|
|
53
|
+
return self.visit_sequence(c, ctx)
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
a = self._visit_method_map[type(c)]
|
|
57
|
+
except KeyError:
|
|
58
|
+
raise TypeError(c) from None
|
|
59
|
+
|
|
60
|
+
return getattr(self, a)(c, ctx)
|
|
61
|
+
|
|
62
|
+
##
|
|
63
|
+
# per-type visit methods
|
|
64
|
+
|
|
65
|
+
def visit_content(self, c: Content, ctx: C) -> R:
|
|
66
|
+
raise TypeError(c)
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
# non-BaseContent
|
|
70
|
+
|
|
71
|
+
def visit_str(self, c: str, ctx: C) -> R:
|
|
72
|
+
return self.visit_content(c, ctx)
|
|
73
|
+
|
|
74
|
+
def visit_sequence(self, c: ta.Sequence[Content], ctx: C) -> R:
|
|
75
|
+
return self.visit_content(c, ctx)
|
|
76
|
+
|
|
77
|
+
##
|
|
78
|
+
# BaseContent
|
|
79
|
+
|
|
80
|
+
def visit_base_content(self, c: BaseContent, ctx: C) -> R:
|
|
81
|
+
return self.visit_content(c, ctx)
|
|
82
|
+
|
|
83
|
+
##
|
|
84
|
+
# StandardContent
|
|
85
|
+
|
|
86
|
+
def visit_standard_content(self, c: StandardContent, ctx: C) -> R:
|
|
87
|
+
return self.visit_base_content(c, ctx)
|
|
88
|
+
|
|
89
|
+
##
|
|
90
|
+
# leaf StandardContent
|
|
91
|
+
|
|
92
|
+
def visit_image_content(self, c: ImageContent, ctx: C) -> R:
|
|
93
|
+
return self.visit_standard_content(c, ctx)
|
|
94
|
+
|
|
95
|
+
def visit_json_content(self, c: JsonContent, ctx: C) -> R:
|
|
96
|
+
return self.visit_standard_content(c, ctx)
|
|
97
|
+
|
|
98
|
+
def visit_link_content(self, c: LinkContent, ctx: C) -> R:
|
|
99
|
+
return self.visit_standard_content(c, ctx)
|
|
100
|
+
|
|
101
|
+
def visit_markdown_content(self, c: MarkdownContent, ctx: C) -> R:
|
|
102
|
+
return self.visit_standard_content(c, ctx)
|
|
103
|
+
|
|
104
|
+
def visit_quote_content(self, c: QuoteContent, ctx: C) -> R:
|
|
105
|
+
return self.visit_standard_content(c, ctx)
|
|
106
|
+
|
|
107
|
+
def visit_text_content(self, c: TextContent, ctx: C) -> R:
|
|
108
|
+
return self.visit_standard_content(c, ctx)
|
|
109
|
+
|
|
110
|
+
##
|
|
111
|
+
# CompositeContent
|
|
112
|
+
|
|
113
|
+
def visit_composite_content(self, c: CompositeContent, ctx: C) -> R:
|
|
114
|
+
return self.visit_standard_content(c, ctx)
|
|
115
|
+
|
|
116
|
+
def visit_section_content(self, c: SectionContent, ctx: C) -> R:
|
|
117
|
+
return self.visit_composite_content(c, ctx)
|
|
118
|
+
|
|
119
|
+
def visit_tag_content(self, c: TagContent, ctx: C) -> R:
|
|
120
|
+
return self.visit_composite_content(c, ctx)
|
|
121
|
+
|
|
122
|
+
##
|
|
123
|
+
# CodeContent
|
|
124
|
+
|
|
125
|
+
def visit_code_content(self, c: CodeContent, ctx: C) -> R:
|
|
126
|
+
return self.visit_standard_content(c, ctx)
|
|
127
|
+
|
|
128
|
+
def visit_inline_code_content(self, c: InlineCodeContent, ctx: C) -> R:
|
|
129
|
+
return self.visit_code_content(c, ctx)
|
|
130
|
+
|
|
131
|
+
def visit_block_code_content(self, c: BlockCodeContent, ctx: C) -> R:
|
|
132
|
+
return self.visit_code_content(c, ctx)
|
|
133
|
+
|
|
134
|
+
##
|
|
135
|
+
# DynamicContent
|
|
136
|
+
|
|
137
|
+
def visit_dynamic_content(self, c: DynamicContent, ctx: C) -> R:
|
|
138
|
+
return self.visit_standard_content(c, ctx)
|
|
139
|
+
|
|
140
|
+
def visit_recursive_content(self, c: RecursiveContent, ctx: C) -> R:
|
|
141
|
+
return self.visit_dynamic_content(c, ctx)
|
|
142
|
+
|
|
143
|
+
def visit_namespace_content(self, c: NamespaceContent, ctx: C) -> R:
|
|
144
|
+
return self.visit_recursive_content(c, ctx)
|
|
145
|
+
|
|
146
|
+
def visit_placeholder_content(self, c: PlaceholderContent, ctx: C) -> R:
|
|
147
|
+
return self.visit_recursive_content(c, ctx)
|
|
148
|
+
|
|
149
|
+
def visit_template_content(self, c: TemplateContent, ctx: C) -> R:
|
|
150
|
+
return self.visit_dynamic_content(c, ctx)
|
|
151
|
+
|
|
152
|
+
##
|
|
153
|
+
# EmphasisContent
|
|
154
|
+
|
|
155
|
+
def visit_emphasis_content(self, c: EmphasisContent, ctx: C) -> R:
|
|
156
|
+
return self.visit_standard_content(c, ctx)
|
|
157
|
+
|
|
158
|
+
def visit_bold_content(self, c: BoldContent, ctx: C) -> R:
|
|
159
|
+
return self.visit_emphasis_content(c, ctx)
|
|
160
|
+
|
|
161
|
+
def visit_italic_content(self, c: ItalicContent, ctx: C) -> R:
|
|
162
|
+
return self.visit_emphasis_content(c, ctx)
|
|
163
|
+
|
|
164
|
+
def visit_bold_italic_content(self, c: BoldItalicContent, ctx: C) -> R:
|
|
165
|
+
return self.visit_emphasis_content(c, ctx)
|
|
166
|
+
|
|
167
|
+
##
|
|
168
|
+
# SequenceContent
|
|
169
|
+
|
|
170
|
+
def visit_sequence_content(self, c: SequenceContent, ctx: C) -> R:
|
|
171
|
+
return self.visit_composite_content(c, ctx)
|
|
172
|
+
|
|
173
|
+
def visit_inline_content(self, c: InlineContent, ctx: C) -> R:
|
|
174
|
+
return self.visit_sequence_content(c, ctx)
|
|
175
|
+
|
|
176
|
+
def visit_block_content(self, c: BlockContent, ctx: C) -> R:
|
|
177
|
+
return self.visit_sequence_content(c, ctx)
|
|
178
|
+
|
|
179
|
+
def visit_item_list_content(self, c: ItemListContent, ctx: C) -> R:
|
|
180
|
+
return self.visit_sequence_content(c, ctx)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
ContentVisitor._visit_method_map = { # noqa
|
|
184
|
+
list(inspect.signature(o).parameters.values())[1].annotation: a
|
|
185
|
+
for a, o in ContentVisitor.__dict__.items()
|
|
186
|
+
if a.startswith('visit_')
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
##
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class StandardContentVisitorTypeError(TypeError):
|
|
194
|
+
pass
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class StandardContentVisitor(ContentVisitor[C, R], lang.Abstract):
|
|
198
|
+
def visit_str(self, c: str, ctx: C) -> R:
|
|
199
|
+
raise StandardContentVisitorTypeError(c)
|
|
200
|
+
|
|
201
|
+
def visit_sequence(self, c: ta.Sequence[Content], ctx: C) -> R:
|
|
202
|
+
raise StandardContentVisitorTypeError(c)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
##
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class StaticContentVisitorTypeError(TypeError):
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class StaticContentVisitor(ContentVisitor[C, R], lang.Abstract):
|
|
213
|
+
def visit_dynamic_content(self, c: DynamicContent, ctx: C) -> R:
|
|
214
|
+
raise StaticContentVisitorTypeError(c)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
##
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class ContentTransform(ContentVisitor[C, Content], lang.Abstract):
|
|
221
|
+
def visit_content(self, c: Content, ctx: C) -> Content:
|
|
222
|
+
return c
|
|
223
|
+
|
|
224
|
+
def visit_sequence(self, c: ta.Sequence[Content], ctx: C) -> Content:
|
|
225
|
+
return [self.visit(cc, ctx) for cc in c]
|
|
226
|
+
|
|
227
|
+
def visit_composite_content(self, c: CompositeContent, ctx: C) -> Content:
|
|
228
|
+
cc = c.child_content()
|
|
229
|
+
ncc = self.visit_sequence(cc, ctx)
|
|
230
|
+
nc = c.replace_child_content(check.isinstance(ncc, collections.abc.Sequence))
|
|
231
|
+
return super().visit_composite_content(nc, ctx)
|
ommlds/minichain/metadata.py
CHANGED
|
@@ -3,9 +3,13 @@ import datetime
|
|
|
3
3
|
import typing as ta
|
|
4
4
|
import uuid
|
|
5
5
|
|
|
6
|
+
from omlish import check
|
|
7
|
+
from omlish import dataclasses as dc
|
|
6
8
|
from omlish import lang
|
|
7
9
|
from omlish import typedvalues as tv
|
|
8
10
|
|
|
11
|
+
from ._typedvalues import _tv_field_metadata
|
|
12
|
+
|
|
9
13
|
|
|
10
14
|
##
|
|
11
15
|
|
|
@@ -31,13 +35,66 @@ class MetadataContainer(
|
|
|
31
35
|
raise NotImplementedError
|
|
32
36
|
|
|
33
37
|
@abc.abstractmethod
|
|
34
|
-
def
|
|
38
|
+
def update_metadata(self, *mds: MetadataT, override: bool = False) -> ta.Self:
|
|
35
39
|
raise NotImplementedError
|
|
36
40
|
|
|
37
41
|
|
|
38
42
|
##
|
|
39
43
|
|
|
40
44
|
|
|
45
|
+
@dc.dataclass(frozen=True)
|
|
46
|
+
class MetadataContainerDataclass( # noqa
|
|
47
|
+
MetadataContainer[MetadataT],
|
|
48
|
+
lang.Abstract,
|
|
49
|
+
):
|
|
50
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
51
|
+
super().__init_subclass__(**kwargs)
|
|
52
|
+
|
|
53
|
+
check.state(hasattr(cls, '_metadata'))
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def _configure_metadata_field(md_fld, md_cls):
|
|
57
|
+
dc.set_field_metadata(
|
|
58
|
+
check.isinstance(md_fld, dc.Field),
|
|
59
|
+
_tv_field_metadata(
|
|
60
|
+
check.not_none(md_cls),
|
|
61
|
+
marshal_name='metadata',
|
|
62
|
+
),
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def metadata(self) -> tv.TypedValues[MetadataT]:
|
|
67
|
+
return check.isinstance(getattr(self, '_metadata'), tv.TypedValues)
|
|
68
|
+
|
|
69
|
+
def discard_metadata(self, *tys: type) -> ta.Self:
|
|
70
|
+
nmd = (md := self.metadata).discard(*tys)
|
|
71
|
+
|
|
72
|
+
if nmd is md:
|
|
73
|
+
return self
|
|
74
|
+
|
|
75
|
+
return dc.replace(self, _metadata=nmd) # type: ignore[call-arg] # noqa
|
|
76
|
+
|
|
77
|
+
def update_metadata(
|
|
78
|
+
self,
|
|
79
|
+
*mds: MetadataT,
|
|
80
|
+
discard: ta.Iterable[type] | None = None,
|
|
81
|
+
override: bool = False,
|
|
82
|
+
) -> ta.Self:
|
|
83
|
+
nmd = (md := self.metadata).update(
|
|
84
|
+
*mds,
|
|
85
|
+
discard=discard,
|
|
86
|
+
override=override,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
if nmd is md:
|
|
90
|
+
return self
|
|
91
|
+
|
|
92
|
+
return dc.replace(self, _metadata=nmd) # type: ignore[call-arg] # noqa
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
##
|
|
96
|
+
|
|
97
|
+
|
|
41
98
|
class CommonMetadata(Metadata, lang.Abstract):
|
|
42
99
|
pass
|
|
43
100
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import typing as ta
|
|
2
2
|
|
|
3
|
+
from ...content.content import Content
|
|
3
4
|
from ...content.transform.materialize import ContentMaterializer
|
|
4
|
-
from ...content.
|
|
5
|
+
from ...content.transform.materialize import DefaultContentMaterializer
|
|
5
6
|
from .context import ToolContext
|
|
6
7
|
from .errors import ToolExecutionError
|
|
7
8
|
from .executors import ToolExecutor
|
|
@@ -15,7 +16,7 @@ class ErrorHandlingToolExecutor(ToolExecutor):
|
|
|
15
16
|
self,
|
|
16
17
|
*,
|
|
17
18
|
wrapped: ToolExecutor,
|
|
18
|
-
content_materializer: ContentMaterializer =
|
|
19
|
+
content_materializer: ContentMaterializer = DefaultContentMaterializer(),
|
|
19
20
|
) -> None:
|
|
20
21
|
super().__init__()
|
|
21
22
|
|
|
@@ -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.
|
|
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
|
ommlds/minichain/tools/fns.py
CHANGED
|
@@ -23,7 +23,7 @@ from omlish import metadata as md
|
|
|
23
23
|
from omlish import reflect as rfl
|
|
24
24
|
from omlish.lite.cached import cached_nullary
|
|
25
25
|
|
|
26
|
-
from ..content.
|
|
26
|
+
from ..content.content import Content
|
|
27
27
|
from .types import EnumToolDtype
|
|
28
28
|
from .types import MappingToolDtype
|
|
29
29
|
from .types import NullableToolDtype
|
ommlds/minichain/tools/types.py
CHANGED
ommlds/tools/git.py
CHANGED
|
@@ -3,15 +3,12 @@ TODO:
|
|
|
3
3
|
- move omit magic to omdev lol
|
|
4
4
|
"""
|
|
5
5
|
import abc
|
|
6
|
-
import concurrent.futures as cf
|
|
7
6
|
import dataclasses as dc
|
|
8
|
-
import os.path
|
|
9
7
|
import re
|
|
10
8
|
import typing as ta
|
|
11
9
|
import urllib.request
|
|
12
10
|
|
|
13
11
|
from omdev.git.magic import GIT_DIFF_OMIT_MAGIC_COMMENT
|
|
14
|
-
from omdev.home.secrets import load_secrets
|
|
15
12
|
from omdev.py.srcheaders import get_py_header_lines
|
|
16
13
|
from omdev.tools.git.messages import GitMessageGenerator
|
|
17
14
|
from omlish import check
|
|
@@ -21,14 +18,10 @@ from omlish.http import all as http
|
|
|
21
18
|
from omlish.subprocesses.sync import subprocesses
|
|
22
19
|
|
|
23
20
|
from .. import minichain as mc
|
|
24
|
-
from ..
|
|
21
|
+
from ..cli.secrets import install_env_secrets
|
|
25
22
|
from ..server.client import McServerClient
|
|
26
23
|
|
|
27
24
|
|
|
28
|
-
with lang.auto_proxy_import(globals()):
|
|
29
|
-
from ..minichain.backends.impls.mlx import chat as mc_mlx_chat
|
|
30
|
-
|
|
31
|
-
|
|
32
25
|
GitAiBackendConfigT = ta.TypeVar('GitAiBackendConfigT', bound='GitAiBackend.Config')
|
|
33
26
|
|
|
34
27
|
|
|
@@ -36,7 +29,7 @@ GitAiBackendConfigT = ta.TypeVar('GitAiBackendConfigT', bound='GitAiBackend.Conf
|
|
|
36
29
|
|
|
37
30
|
|
|
38
31
|
class GitAiBackend(Configurable[GitAiBackendConfigT], lang.Abstract):
|
|
39
|
-
@dc.dataclass(frozen=True)
|
|
32
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
|
40
33
|
class Config(Configurable.Config):
|
|
41
34
|
max_tokens: int | None = 128
|
|
42
35
|
|
|
@@ -64,22 +57,35 @@ def _get_single_ai_message_str(resp: mc.ChatChoicesResponse) -> str:
|
|
|
64
57
|
#
|
|
65
58
|
|
|
66
59
|
|
|
67
|
-
class
|
|
68
|
-
@dc.dataclass(frozen=True)
|
|
60
|
+
class StandardGitAiBackend(GitAiBackend['StandardGitAiBackend.Config']):
|
|
61
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
|
69
62
|
class Config(GitAiBackend.Config):
|
|
70
|
-
|
|
63
|
+
backend: str | None = None
|
|
71
64
|
|
|
72
|
-
|
|
65
|
+
DEFAULT_BACKEND_NAME: str = 'openai'
|
|
66
|
+
|
|
67
|
+
def __init__(
|
|
68
|
+
self,
|
|
69
|
+
config: Config = Config(),
|
|
70
|
+
*,
|
|
71
|
+
backend_catalog: ta.Optional['mc.BackendCatalog'] = None,
|
|
72
|
+
) -> None:
|
|
73
73
|
super().__init__(config)
|
|
74
74
|
|
|
75
|
+
if backend_catalog is None:
|
|
76
|
+
backend_catalog = mc.BackendStringBackendCatalog()
|
|
77
|
+
self._backend_catalog = backend_catalog
|
|
78
|
+
|
|
75
79
|
def run_prompt(self, prompt: str) -> str:
|
|
76
|
-
# FIXME
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
install_env_secrets() # FIXME
|
|
81
|
+
|
|
82
|
+
be = self._backend_catalog.get_backend(
|
|
83
|
+
mc.ChatChoicesService, # type: ignore[type-abstract]
|
|
84
|
+
self._config.backend or self.DEFAULT_BACKEND_NAME,
|
|
85
|
+
)
|
|
80
86
|
|
|
81
|
-
llm =
|
|
82
|
-
http_client=http.SyncAsyncHttpClient(http.client()),
|
|
87
|
+
llm = be.factory(
|
|
88
|
+
http_client=http.SyncAsyncHttpClient(http.client()), # FIXME
|
|
83
89
|
)
|
|
84
90
|
|
|
85
91
|
resp = lang.sync_await(llm.invoke(mc.ChatChoicesRequest(
|
|
@@ -98,51 +104,51 @@ def _strip_markdown_code_block(text: str) -> str:
|
|
|
98
104
|
return match.group(1)
|
|
99
105
|
|
|
100
106
|
|
|
101
|
-
class MlxGitAiBackend(GitAiBackend['MlxGitAiBackend.Config']):
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
107
|
+
# class MlxGitAiBackend(GitAiBackend['MlxGitAiBackend.Config']):
|
|
108
|
+
# @dc.dataclass(frozen=True, kw_only=True)
|
|
109
|
+
# class Config(GitAiBackend.Config):
|
|
110
|
+
# model: str = 'mlx-community/Qwen2.5-Coder-32B-Instruct-8bit'
|
|
111
|
+
#
|
|
112
|
+
# run_in_subprocess: bool = True
|
|
113
|
+
# subprocess_timeout: float | None = 60.
|
|
114
|
+
#
|
|
115
|
+
# def __init__(self, config: Config = Config()) -> None:
|
|
116
|
+
# super().__init__(config)
|
|
117
|
+
#
|
|
118
|
+
# def _run_prompt(self, prompt: str) -> str:
|
|
119
|
+
# with mc_mlx_chat.MlxChatChoicesService(mc.ModelRepo.parse(self._config.model)) as llm:
|
|
120
|
+
# resp = lang.sync_await(llm.invoke(mc.ChatChoicesRequest(
|
|
121
|
+
# [mc.UserMessage(prompt)],
|
|
122
|
+
# # FIXME: *((MaxTokens(self._config.max_tokens),) if self._config.max_tokens is not None else ()),
|
|
123
|
+
# )))
|
|
124
|
+
# text = _get_single_ai_message_str(resp)
|
|
125
|
+
#
|
|
126
|
+
# text = _strip_markdown_code_block(text)
|
|
127
|
+
#
|
|
128
|
+
# return text
|
|
129
|
+
#
|
|
130
|
+
# def run_prompt(self, prompt: str) -> str:
|
|
131
|
+
# if self._config.run_in_subprocess:
|
|
132
|
+
# # tokenizers installs a pthread_atfork callback at *import* time:
|
|
133
|
+
# # https://github.com/huggingface/tokenizers/blob/4f1a810aa258d287e6936315e63fbf58bde2a980/bindings/python/src/lib.rs#L57 # noqa
|
|
134
|
+
# # then complains about `TOKENIZERS_PARALLELISM` at the next fork (which presumably will happen immediately
|
|
135
|
+
# # after this to `git commit`, despite it being conceptually just a fork/exe).
|
|
136
|
+
# # TODO: a generic subprocessing minichain service wrapper?
|
|
137
|
+
# with cf.ProcessPoolExecutor() as exe:
|
|
138
|
+
# return exe.submit(
|
|
139
|
+
# self._run_prompt,
|
|
140
|
+
# prompt,
|
|
141
|
+
# ).result(timeout=self._config.subprocess_timeout)
|
|
142
|
+
#
|
|
143
|
+
# else:
|
|
144
|
+
# return self._run_prompt(prompt)
|
|
139
145
|
|
|
140
146
|
|
|
141
147
|
#
|
|
142
148
|
|
|
143
149
|
|
|
144
150
|
class LocalhostHttpPostGitAiBackend(GitAiBackend['LocalhostHttpPostGitAiBackend.Config']):
|
|
145
|
-
@dc.dataclass(frozen=True)
|
|
151
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
|
146
152
|
class Config(GitAiBackend.Config):
|
|
147
153
|
port: int = 5067
|
|
148
154
|
path: str = ''
|
|
@@ -166,7 +172,7 @@ class LocalhostHttpPostGitAiBackend(GitAiBackend['LocalhostHttpPostGitAiBackend.
|
|
|
166
172
|
|
|
167
173
|
|
|
168
174
|
class McServerGitAiBackend(GitAiBackend['McServerGitAiBackend.Config']):
|
|
169
|
-
@dc.dataclass(frozen=True)
|
|
175
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
|
170
176
|
class Config(GitAiBackend.Config):
|
|
171
177
|
pass
|
|
172
178
|
|
|
@@ -192,18 +198,23 @@ class AiGitMessageGenerator(GitMessageGenerator):
|
|
|
192
198
|
def __init__(
|
|
193
199
|
self,
|
|
194
200
|
*,
|
|
195
|
-
backend: GitAiBackend | None = None,
|
|
201
|
+
backend: GitAiBackend | str | None = None,
|
|
196
202
|
) -> None:
|
|
197
203
|
super().__init__()
|
|
198
204
|
|
|
199
205
|
if backend is None:
|
|
200
206
|
backend = self.DEFAULT_BACKEND
|
|
201
|
-
|
|
207
|
+
elif isinstance(backend, str):
|
|
208
|
+
backend = StandardGitAiBackend(
|
|
209
|
+
config=StandardGitAiBackend.Config(
|
|
210
|
+
backend=backend,
|
|
211
|
+
),
|
|
212
|
+
)
|
|
213
|
+
self._backend = check.isinstance(backend, GitAiBackend)
|
|
202
214
|
|
|
203
215
|
DEFAULT_BACKEND: ta.ClassVar[GitAiBackend] = (
|
|
204
|
-
|
|
216
|
+
StandardGitAiBackend()
|
|
205
217
|
# LocalhostHttpPostGitAiBackend()
|
|
206
|
-
# MlxGitAiBackend()
|
|
207
218
|
# McServerGitAiBackend()
|
|
208
219
|
)
|
|
209
220
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ommlds
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev498
|
|
4
4
|
Summary: ommlds
|
|
5
5
|
Author: wrmsr
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -14,9 +14,9 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
14
14
|
Requires-Python: >=3.13
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: omlish==0.0.0.
|
|
17
|
+
Requires-Dist: omlish==0.0.0.dev498
|
|
18
18
|
Provides-Extra: all
|
|
19
|
-
Requires-Dist: omdev==0.0.0.
|
|
19
|
+
Requires-Dist: omdev==0.0.0.dev498; extra == "all"
|
|
20
20
|
Requires-Dist: llama-cpp-python~=0.3; extra == "all"
|
|
21
21
|
Requires-Dist: mlx~=0.30; sys_platform == "darwin" and extra == "all"
|
|
22
22
|
Requires-Dist: mlx-lm~=0.29; sys_platform == "darwin" and extra == "all"
|
|
@@ -38,7 +38,7 @@ Requires-Dist: mwparserfromhell~=0.7; extra == "all"
|
|
|
38
38
|
Requires-Dist: wikitextparser~=0.56; extra == "all"
|
|
39
39
|
Requires-Dist: lxml>=5.3; python_version < "3.13" and extra == "all"
|
|
40
40
|
Provides-Extra: omdev
|
|
41
|
-
Requires-Dist: omdev==0.0.0.
|
|
41
|
+
Requires-Dist: omdev==0.0.0.dev498; extra == "omdev"
|
|
42
42
|
Provides-Extra: backends
|
|
43
43
|
Requires-Dist: llama-cpp-python~=0.3; extra == "backends"
|
|
44
44
|
Requires-Dist: mlx~=0.30; sys_platform == "darwin" and extra == "backends"
|