ommlds 0.0.0.dev456__py3-none-any.whl → 0.0.0.dev485__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 +314 -33
- ommlds/__about__.py +15 -9
- ommlds/_hacks/__init__.py +4 -0
- ommlds/_hacks/funcs.py +110 -0
- ommlds/_hacks/names.py +158 -0
- ommlds/_hacks/params.py +73 -0
- ommlds/_hacks/patches.py +0 -3
- ommlds/backends/anthropic/protocol/__init__.py +13 -1
- ommlds/backends/anthropic/protocol/_dataclasses.py +1625 -0
- ommlds/backends/anthropic/protocol/sse/assemble.py +22 -6
- ommlds/backends/anthropic/protocol/sse/events.py +13 -0
- ommlds/backends/google/protocol/__init__.py +13 -0
- ommlds/backends/google/protocol/_dataclasses.py +5997 -0
- ommlds/backends/google/protocol/types.py +5 -1
- ommlds/backends/groq/__init__.py +7 -0
- ommlds/backends/groq/_dataclasses.py +3901 -0
- ommlds/backends/groq/_marshal.py +23 -0
- ommlds/backends/groq/protocol.py +249 -0
- ommlds/backends/llamacpp/logging.py +4 -1
- ommlds/backends/mlx/caching.py +7 -3
- ommlds/backends/mlx/cli.py +10 -7
- ommlds/backends/mlx/generation.py +18 -16
- ommlds/backends/mlx/limits.py +10 -6
- ommlds/backends/mlx/loading.py +65 -5
- ommlds/backends/ollama/__init__.py +7 -0
- ommlds/backends/ollama/_dataclasses.py +3458 -0
- ommlds/backends/ollama/protocol.py +170 -0
- ommlds/backends/openai/protocol/__init__.py +15 -1
- ommlds/backends/openai/protocol/_dataclasses.py +7708 -0
- ommlds/backends/tavily/__init__.py +7 -0
- ommlds/backends/tavily/_dataclasses.py +1734 -0
- ommlds/backends/tavily/protocol.py +301 -0
- ommlds/backends/tinygrad/models/llama3/__init__.py +22 -14
- ommlds/backends/transformers/__init__.py +14 -0
- ommlds/backends/transformers/filecache.py +109 -0
- ommlds/backends/transformers/streamers.py +73 -0
- ommlds/cli/__init__.py +7 -0
- ommlds/cli/_dataclasses.py +2562 -0
- ommlds/cli/asyncs.py +30 -0
- ommlds/cli/backends/catalog.py +93 -0
- ommlds/cli/backends/configs.py +9 -0
- ommlds/cli/backends/inject.py +31 -36
- ommlds/cli/backends/injection.py +16 -0
- ommlds/cli/backends/types.py +46 -0
- ommlds/cli/content/messages.py +34 -0
- ommlds/cli/content/strings.py +42 -0
- ommlds/cli/inject.py +15 -32
- ommlds/cli/inputs/__init__.py +0 -0
- ommlds/cli/inputs/asyncs.py +32 -0
- ommlds/cli/inputs/sync.py +75 -0
- ommlds/cli/main.py +267 -128
- ommlds/cli/rendering/__init__.py +0 -0
- ommlds/cli/rendering/configs.py +9 -0
- ommlds/cli/rendering/inject.py +31 -0
- ommlds/cli/rendering/markdown.py +52 -0
- ommlds/cli/rendering/raw.py +73 -0
- ommlds/cli/rendering/types.py +21 -0
- ommlds/cli/secrets.py +21 -0
- ommlds/cli/sessions/base.py +1 -1
- ommlds/cli/sessions/chat/chat/__init__.py +0 -0
- ommlds/cli/sessions/chat/chat/ai/__init__.py +0 -0
- ommlds/cli/sessions/chat/chat/ai/configs.py +11 -0
- ommlds/cli/sessions/chat/chat/ai/inject.py +74 -0
- ommlds/cli/sessions/chat/chat/ai/injection.py +14 -0
- ommlds/cli/sessions/chat/chat/ai/rendering.py +70 -0
- ommlds/cli/sessions/chat/chat/ai/services.py +79 -0
- ommlds/cli/sessions/chat/chat/ai/tools.py +44 -0
- ommlds/cli/sessions/chat/chat/ai/types.py +28 -0
- ommlds/cli/sessions/chat/chat/state/__init__.py +0 -0
- ommlds/cli/sessions/chat/chat/state/configs.py +11 -0
- ommlds/cli/sessions/chat/chat/state/inject.py +36 -0
- ommlds/cli/sessions/chat/chat/state/inmemory.py +33 -0
- ommlds/cli/sessions/chat/chat/state/storage.py +52 -0
- ommlds/cli/sessions/chat/chat/state/types.py +38 -0
- ommlds/cli/sessions/chat/chat/user/__init__.py +0 -0
- ommlds/cli/sessions/chat/chat/user/configs.py +17 -0
- ommlds/cli/sessions/chat/chat/user/inject.py +62 -0
- ommlds/cli/sessions/chat/chat/user/interactive.py +31 -0
- ommlds/cli/sessions/chat/chat/user/oneshot.py +25 -0
- ommlds/cli/sessions/chat/chat/user/types.py +15 -0
- ommlds/cli/sessions/chat/configs.py +27 -0
- ommlds/cli/sessions/chat/driver.py +43 -0
- ommlds/cli/sessions/chat/inject.py +33 -65
- ommlds/cli/sessions/chat/phases/__init__.py +0 -0
- ommlds/cli/sessions/chat/phases/inject.py +27 -0
- ommlds/cli/sessions/chat/phases/injection.py +14 -0
- ommlds/cli/sessions/chat/phases/manager.py +29 -0
- ommlds/cli/sessions/chat/phases/types.py +29 -0
- ommlds/cli/sessions/chat/session.py +27 -0
- ommlds/cli/sessions/chat/tools/__init__.py +0 -0
- ommlds/cli/sessions/chat/tools/configs.py +22 -0
- ommlds/cli/sessions/chat/tools/confirmation.py +46 -0
- ommlds/cli/sessions/chat/tools/execution.py +66 -0
- ommlds/cli/sessions/chat/tools/fs/__init__.py +0 -0
- ommlds/cli/sessions/chat/tools/fs/configs.py +12 -0
- ommlds/cli/sessions/chat/tools/fs/inject.py +35 -0
- ommlds/cli/sessions/chat/tools/inject.py +88 -0
- ommlds/cli/sessions/chat/tools/injection.py +44 -0
- ommlds/cli/sessions/chat/tools/rendering.py +58 -0
- ommlds/cli/sessions/chat/tools/todo/__init__.py +0 -0
- ommlds/cli/sessions/chat/tools/todo/configs.py +12 -0
- ommlds/cli/sessions/chat/tools/todo/inject.py +31 -0
- ommlds/cli/sessions/chat/tools/weather/__init__.py +0 -0
- ommlds/cli/sessions/chat/tools/weather/configs.py +12 -0
- ommlds/cli/sessions/chat/tools/weather/inject.py +22 -0
- ommlds/cli/{tools/weather.py → sessions/chat/tools/weather/tools.py} +1 -1
- ommlds/cli/sessions/completion/configs.py +21 -0
- ommlds/cli/sessions/completion/inject.py +42 -0
- ommlds/cli/sessions/completion/session.py +35 -0
- ommlds/cli/sessions/embedding/configs.py +21 -0
- ommlds/cli/sessions/embedding/inject.py +42 -0
- ommlds/cli/sessions/embedding/session.py +33 -0
- ommlds/cli/sessions/inject.py +28 -11
- ommlds/cli/state/__init__.py +0 -0
- ommlds/cli/state/inject.py +28 -0
- ommlds/cli/{state.py → state/storage.py} +41 -24
- ommlds/minichain/__init__.py +46 -17
- ommlds/minichain/_dataclasses.py +15401 -0
- ommlds/minichain/backends/catalogs/base.py +20 -1
- ommlds/minichain/backends/catalogs/simple.py +2 -2
- ommlds/minichain/backends/catalogs/strings.py +10 -8
- ommlds/minichain/backends/impls/anthropic/chat.py +31 -65
- ommlds/minichain/backends/impls/anthropic/names.py +3 -4
- ommlds/minichain/backends/impls/anthropic/protocol.py +109 -0
- ommlds/minichain/backends/impls/anthropic/stream.py +53 -31
- ommlds/minichain/backends/impls/duckduckgo/search.py +5 -1
- ommlds/minichain/backends/impls/dummy/__init__.py +0 -0
- ommlds/minichain/backends/impls/dummy/chat.py +69 -0
- ommlds/minichain/backends/impls/google/chat.py +9 -2
- ommlds/minichain/backends/impls/google/search.py +6 -1
- ommlds/minichain/backends/impls/google/stream.py +122 -32
- ommlds/minichain/backends/impls/groq/__init__.py +0 -0
- ommlds/minichain/backends/impls/groq/chat.py +75 -0
- ommlds/minichain/backends/impls/groq/names.py +48 -0
- ommlds/minichain/backends/impls/groq/protocol.py +143 -0
- ommlds/minichain/backends/impls/groq/stream.py +125 -0
- ommlds/minichain/backends/impls/huggingface/repos.py +1 -5
- ommlds/minichain/backends/impls/llamacpp/chat.py +15 -3
- ommlds/minichain/backends/impls/llamacpp/completion.py +7 -3
- ommlds/minichain/backends/impls/llamacpp/stream.py +38 -19
- ommlds/minichain/backends/impls/mistral.py +9 -2
- ommlds/minichain/backends/impls/mlx/chat.py +100 -23
- ommlds/minichain/backends/impls/ollama/__init__.py +0 -0
- ommlds/minichain/backends/impls/ollama/chat.py +199 -0
- ommlds/minichain/backends/impls/openai/chat.py +14 -7
- ommlds/minichain/backends/impls/openai/completion.py +9 -2
- ommlds/minichain/backends/impls/openai/embedding.py +9 -2
- ommlds/minichain/backends/impls/openai/format.py +115 -109
- ommlds/minichain/backends/impls/openai/names.py +31 -5
- ommlds/minichain/backends/impls/openai/stream.py +33 -27
- ommlds/minichain/backends/impls/sentencepiece/tokens.py +9 -6
- ommlds/minichain/backends/impls/tavily.py +66 -0
- ommlds/minichain/backends/impls/tinygrad/chat.py +17 -14
- ommlds/minichain/backends/impls/tokenizers/tokens.py +9 -6
- ommlds/minichain/backends/impls/transformers/sentence.py +5 -2
- ommlds/minichain/backends/impls/transformers/tokens.py +10 -7
- ommlds/minichain/backends/impls/transformers/transformers.py +139 -20
- ommlds/minichain/backends/strings/parsing.py +1 -1
- ommlds/minichain/backends/strings/resolving.py +4 -1
- ommlds/minichain/chat/choices/stream/__init__.py +0 -0
- ommlds/minichain/chat/choices/stream/adapters.py +35 -0
- ommlds/minichain/chat/choices/stream/joining.py +31 -0
- ommlds/minichain/chat/choices/stream/services.py +45 -0
- ommlds/minichain/chat/choices/stream/types.py +43 -0
- ommlds/minichain/chat/stream/_marshal.py +4 -4
- ommlds/minichain/chat/stream/joining.py +85 -0
- ommlds/minichain/chat/stream/services.py +15 -15
- ommlds/minichain/chat/stream/types.py +24 -18
- ommlds/minichain/llms/types.py +4 -0
- ommlds/minichain/registries/globals.py +18 -4
- ommlds/minichain/resources.py +28 -3
- ommlds/minichain/search.py +1 -1
- ommlds/minichain/standard.py +8 -0
- ommlds/minichain/stream/services.py +19 -16
- ommlds/minichain/tools/reflect.py +5 -1
- ommlds/nanochat/LICENSE +21 -0
- ommlds/nanochat/__init__.py +0 -0
- ommlds/nanochat/rustbpe/LICENSE +21 -0
- ommlds/nanochat/tokenizers.py +406 -0
- ommlds/specs/__init__.py +0 -0
- ommlds/specs/mcp/__init__.py +0 -0
- ommlds/specs/mcp/_marshal.py +23 -0
- ommlds/specs/mcp/clients.py +146 -0
- ommlds/specs/mcp/protocol.py +371 -0
- ommlds/tools/git.py +13 -6
- ommlds/tools/ocr.py +1 -8
- ommlds/wiki/analyze.py +2 -2
- ommlds/wiki/text/mfh.py +1 -5
- ommlds/wiki/text/wtp.py +1 -3
- ommlds/wiki/utils/xml.py +5 -5
- {ommlds-0.0.0.dev456.dist-info → ommlds-0.0.0.dev485.dist-info}/METADATA +22 -19
- {ommlds-0.0.0.dev456.dist-info → ommlds-0.0.0.dev485.dist-info}/RECORD +198 -95
- ommlds/cli/backends/standard.py +0 -20
- ommlds/cli/sessions/chat/base.py +0 -42
- ommlds/cli/sessions/chat/code.py +0 -129
- ommlds/cli/sessions/chat/interactive.py +0 -71
- ommlds/cli/sessions/chat/printing.py +0 -97
- ommlds/cli/sessions/chat/prompt.py +0 -151
- ommlds/cli/sessions/chat/state.py +0 -110
- ommlds/cli/sessions/chat/tools.py +0 -100
- ommlds/cli/sessions/completion/completion.py +0 -44
- ommlds/cli/sessions/embedding/embedding.py +0 -42
- ommlds/cli/tools/config.py +0 -14
- ommlds/cli/tools/inject.py +0 -75
- ommlds/minichain/backends/impls/openai/format2.py +0 -210
- ommlds/minichain/chat/stream/adapters.py +0 -80
- /ommlds/{huggingface.py → backends/huggingface.py} +0 -0
- /ommlds/cli/{tools → content}/__init__.py +0 -0
- {ommlds-0.0.0.dev456.dist-info → ommlds-0.0.0.dev485.dist-info}/WHEEL +0 -0
- {ommlds-0.0.0.dev456.dist-info → ommlds-0.0.0.dev485.dist-info}/entry_points.txt +0 -0
- {ommlds-0.0.0.dev456.dist-info → ommlds-0.0.0.dev485.dist-info}/licenses/LICENSE +0 -0
- {ommlds-0.0.0.dev456.dist-info → ommlds-0.0.0.dev485.dist-info}/top_level.txt +0 -0
ommlds/cli/asyncs.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import functools
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
from omlish import lang
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
with lang.auto_proxy_import(globals()):
|
|
9
|
+
import anyio
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
T = ta.TypeVar('T')
|
|
13
|
+
P = ta.ParamSpec('P')
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AsyncThreadRunner(lang.Abstract):
|
|
20
|
+
@abc.abstractmethod
|
|
21
|
+
def run_in_thread(self, fn: ta.Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> ta.Awaitable[T]:
|
|
22
|
+
raise NotImplementedError
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AnyioAsyncThreadRunner(AsyncThreadRunner):
|
|
29
|
+
def run_in_thread(self, fn: ta.Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> ta.Awaitable[T]:
|
|
30
|
+
return anyio.to_thread.run_sync(functools.partial(fn, *args, **kwargs))
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from omlish import lang
|
|
5
|
+
|
|
6
|
+
from ... import minichain as mc
|
|
7
|
+
from .types import BackendConfigs
|
|
8
|
+
from .types import BackendName
|
|
9
|
+
from .types import BackendProvider
|
|
10
|
+
from .types import ChatChoicesServiceBackendProvider
|
|
11
|
+
from .types import ChatChoicesStreamServiceBackendProvider
|
|
12
|
+
from .types import CompletionServiceBackendProvider
|
|
13
|
+
from .types import DefaultBackendName
|
|
14
|
+
from .types import EmbeddingServiceBackendProvider
|
|
15
|
+
from .types import ServiceT
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CatalogBackendProvider(BackendProvider[ServiceT], lang.Abstract):
|
|
22
|
+
class Instantiator(lang.Func2['mc.BackendCatalog.Backend', BackendConfigs | None, ta.Awaitable[ta.Any]]):
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
*,
|
|
28
|
+
name: BackendName | None = None,
|
|
29
|
+
default_name: DefaultBackendName | None = None,
|
|
30
|
+
catalog: 'mc.BackendCatalog',
|
|
31
|
+
configs: BackendConfigs | None = None,
|
|
32
|
+
instantiator: Instantiator | None = None,
|
|
33
|
+
) -> None:
|
|
34
|
+
super().__init__()
|
|
35
|
+
|
|
36
|
+
self._name = name
|
|
37
|
+
self._default_name = default_name
|
|
38
|
+
self._catalog = catalog
|
|
39
|
+
self._configs = configs
|
|
40
|
+
if instantiator is None:
|
|
41
|
+
instantiator = CatalogBackendProvider.Instantiator(lang.as_async(lambda be, cfgs: be.factory(*cfgs or [])))
|
|
42
|
+
self._instantiator = instantiator
|
|
43
|
+
|
|
44
|
+
@contextlib.asynccontextmanager
|
|
45
|
+
async def _provide_backend(self, cls: type[ServiceT]) -> ta.AsyncIterator[ServiceT]:
|
|
46
|
+
name: str
|
|
47
|
+
if self._name is not None:
|
|
48
|
+
name = self._name
|
|
49
|
+
elif self._default_name is not None:
|
|
50
|
+
name = self._default_name
|
|
51
|
+
else:
|
|
52
|
+
raise RuntimeError('No backend name specified')
|
|
53
|
+
|
|
54
|
+
be = self._catalog.get_backend(cls, name)
|
|
55
|
+
|
|
56
|
+
service: ServiceT
|
|
57
|
+
async with lang.async_or_sync_maybe_managing(await self._instantiator(be, self._configs)) as service:
|
|
58
|
+
yield service
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
##
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class CatalogChatChoicesServiceBackendProvider(
|
|
65
|
+
CatalogBackendProvider['mc.ChatChoicesService'],
|
|
66
|
+
ChatChoicesServiceBackendProvider,
|
|
67
|
+
):
|
|
68
|
+
def provide_backend(self) -> ta.AsyncContextManager['mc.ChatChoicesService']:
|
|
69
|
+
return self._provide_backend(mc.ChatChoicesService) # type: ignore[type-abstract]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class CatalogChatChoicesStreamServiceBackendProvider(
|
|
73
|
+
CatalogBackendProvider['mc.ChatChoicesStreamService'],
|
|
74
|
+
ChatChoicesStreamServiceBackendProvider,
|
|
75
|
+
):
|
|
76
|
+
def provide_backend(self) -> ta.AsyncContextManager['mc.ChatChoicesStreamService']:
|
|
77
|
+
return self._provide_backend(mc.ChatChoicesStreamService) # type: ignore[type-abstract]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class CatalogCompletionServiceBackendProvider(
|
|
81
|
+
CatalogBackendProvider['mc.CompletionService'],
|
|
82
|
+
CompletionServiceBackendProvider,
|
|
83
|
+
):
|
|
84
|
+
def provide_backend(self) -> ta.AsyncContextManager['mc.CompletionService']:
|
|
85
|
+
return self._provide_backend(mc.CompletionService) # type: ignore[type-abstract]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class CatalogEmbeddingServiceBackendProvider(
|
|
89
|
+
CatalogBackendProvider['mc.EmbeddingService'],
|
|
90
|
+
EmbeddingServiceBackendProvider,
|
|
91
|
+
):
|
|
92
|
+
def provide_backend(self) -> ta.AsyncContextManager['mc.EmbeddingService']:
|
|
93
|
+
return self._provide_backend(mc.EmbeddingService) # type: ignore[type-abstract]
|
ommlds/cli/backends/inject.py
CHANGED
|
@@ -2,69 +2,64 @@ import typing as ta
|
|
|
2
2
|
|
|
3
3
|
from omlish import inject as inj
|
|
4
4
|
from omlish import lang
|
|
5
|
+
from omlish import typedvalues as tv
|
|
5
6
|
|
|
6
7
|
from ... import minichain as mc
|
|
8
|
+
from .configs import BackendConfig
|
|
9
|
+
from .injection import backend_configs
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
with lang.auto_proxy_import(globals()):
|
|
13
|
+
from ...minichain.backends.impls.huggingface import repos as hf_repos
|
|
14
|
+
from . import catalog as _catalog
|
|
15
|
+
from . import types as _types
|
|
7
16
|
|
|
8
17
|
|
|
9
18
|
##
|
|
10
19
|
|
|
11
20
|
|
|
12
|
-
def
|
|
21
|
+
def bind_backends(cfg: BackendConfig = BackendConfig()) -> inj.Elements:
|
|
13
22
|
lst: list[inj.Elemental] = []
|
|
14
23
|
|
|
24
|
+
#
|
|
25
|
+
|
|
15
26
|
lst.extend([
|
|
16
27
|
inj.bind(mc.BackendStringBackendCatalog, singleton=True),
|
|
17
28
|
inj.bind(mc.BackendCatalog, to_key=mc.BackendStringBackendCatalog),
|
|
18
29
|
])
|
|
19
30
|
|
|
20
|
-
from ...minichain.backends.impls.huggingface.repos import HuggingfaceModelRepoResolver
|
|
21
|
-
|
|
22
31
|
lst.extend([
|
|
23
|
-
inj.bind(HuggingfaceModelRepoResolver, singleton=True),
|
|
24
|
-
inj.bind(mc.ModelRepoResolver, to_key=HuggingfaceModelRepoResolver),
|
|
32
|
+
inj.bind(hf_repos.HuggingfaceModelRepoResolver, singleton=True),
|
|
33
|
+
inj.bind(mc.ModelRepoResolver, to_key=hf_repos.HuggingfaceModelRepoResolver),
|
|
25
34
|
|
|
26
35
|
])
|
|
27
36
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def bind_simple_backends() -> inj.Elements:
|
|
32
|
-
lst: list[inj.Elemental] = []
|
|
37
|
+
#
|
|
33
38
|
|
|
34
|
-
lst.
|
|
35
|
-
inj.set_binder[mc.SimpleBackendCatalogEntry](),
|
|
36
|
-
inj.bind(
|
|
37
|
-
lang.typed_lambda(mc.SimpleBackendCatalogEntries, s=ta.AbstractSet[mc.SimpleBackendCatalogEntry])(
|
|
38
|
-
lambda s: list(s),
|
|
39
|
-
),
|
|
40
|
-
singleton=True,
|
|
41
|
-
),
|
|
42
|
-
])
|
|
39
|
+
lst.append(backend_configs().bind_items_provider(singleton=True))
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
inj.bind(mc.SimpleBackendCatalog, singleton=True),
|
|
46
|
-
inj.bind(mc.BackendCatalog, to_key=mc.SimpleBackendCatalog),
|
|
47
|
-
])
|
|
41
|
+
#
|
|
48
42
|
|
|
49
|
-
|
|
43
|
+
if cfg.backend is not None:
|
|
44
|
+
lst.append(inj.bind(_types.BackendName, to_const=cfg.backend))
|
|
50
45
|
|
|
51
46
|
lst.extend([
|
|
52
|
-
inj.
|
|
53
|
-
|
|
47
|
+
inj.bind(_types.ChatChoicesServiceBackendProvider, to_ctor=_catalog.CatalogChatChoicesServiceBackendProvider, singleton=True), # noqa
|
|
48
|
+
inj.bind(_types.ChatChoicesStreamServiceBackendProvider, to_ctor=_catalog.CatalogChatChoicesStreamServiceBackendProvider, singleton=True), # noqa
|
|
49
|
+
inj.bind(_types.CompletionServiceBackendProvider, to_ctor=_catalog.CatalogCompletionServiceBackendProvider, singleton=True), # noqa
|
|
50
|
+
inj.bind(_types.EmbeddingServiceBackendProvider, to_ctor=_catalog.CatalogEmbeddingServiceBackendProvider, singleton=True), # noqa
|
|
54
51
|
])
|
|
55
52
|
|
|
56
|
-
|
|
53
|
+
#
|
|
57
54
|
|
|
55
|
+
async def catalog_backend_instantiator_provider(injector: inj.AsyncInjector) -> _catalog.CatalogBackendProvider.Instantiator: # noqa
|
|
56
|
+
async def inner(be: 'mc.BackendCatalog.Backend', cfgs: _types.BackendConfigs | None) -> ta.Any:
|
|
57
|
+
kwt = inj.build_kwargs_target(be.factory, non_strict=True)
|
|
58
|
+
kw = await injector.provide_kwargs(kwt)
|
|
59
|
+
return be.factory(*tv.collect(*(be.configs or []), *(cfgs or []), override=True), **kw)
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
*,
|
|
61
|
-
enable_backend_strings: bool = False,
|
|
62
|
-
) -> inj.Elements:
|
|
63
|
-
lst: list[inj.Elemental] = []
|
|
61
|
+
return _catalog.CatalogBackendProvider.Instantiator(inner)
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
lst.append(bind_strings_backends())
|
|
67
|
-
else:
|
|
68
|
-
lst.append(bind_simple_backends())
|
|
63
|
+
lst.append(inj.bind(_catalog.CatalogBackendProvider.Instantiator, to_async_fn=catalog_backend_instantiator_provider)) # noqa
|
|
69
64
|
|
|
70
65
|
return inj.as_elements(*lst)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from omlish import inject as inj
|
|
2
|
+
from omlish import lang
|
|
3
|
+
|
|
4
|
+
from ... import minichain as mc
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
with lang.auto_proxy_import(globals()):
|
|
8
|
+
from . import types as _types
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@lang.cached_function
|
|
15
|
+
def backend_configs() -> 'inj.ItemsBinderHelper[mc.Config]':
|
|
16
|
+
return inj.items_binder_helper[mc.Config](_types.BackendConfigs)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from omlish import lang
|
|
5
|
+
|
|
6
|
+
from ... import minichain as mc
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
ServiceT = ta.TypeVar('ServiceT', bound=mc.Service)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
BackendName = ta.NewType('BackendName', str)
|
|
16
|
+
DefaultBackendName = ta.NewType('DefaultBackendName', str)
|
|
17
|
+
|
|
18
|
+
BackendConfigs = ta.NewType('BackendConfigs', ta.Sequence['mc.Config'])
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class BackendProvider(lang.Abstract, ta.Generic[ServiceT]):
|
|
25
|
+
@abc.abstractmethod
|
|
26
|
+
def provide_backend(self) -> ta.AsyncContextManager[ServiceT]:
|
|
27
|
+
raise NotImplementedError
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ChatChoicesServiceBackendProvider(BackendProvider['mc.ChatChoicesService'], lang.Abstract):
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ChatChoicesStreamServiceBackendProvider(BackendProvider['mc.ChatChoicesStreamService'], lang.Abstract):
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class CompletionServiceBackendProvider(BackendProvider['mc.CompletionService'], lang.Abstract):
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class EmbeddingServiceBackendProvider(BackendProvider['mc.EmbeddingService'], lang.Abstract):
|
|
46
|
+
pass
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from omlish import check
|
|
5
|
+
from omlish import lang
|
|
6
|
+
|
|
7
|
+
from ... import minichain as mc
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MessageContentExtractor(lang.Abstract):
|
|
14
|
+
@abc.abstractmethod
|
|
15
|
+
def extract_message_content(self, message: 'mc.Message') -> ta.Optional['mc.Content']:
|
|
16
|
+
raise NotImplementedError
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MessageContentExtractorImpl(MessageContentExtractor):
|
|
20
|
+
def extract_message_content(self, message: 'mc.Message') -> ta.Optional['mc.Content']:
|
|
21
|
+
if isinstance(message, (mc.SystemMessage, mc.UserMessage, mc.AiMessage)):
|
|
22
|
+
if message.c is not None:
|
|
23
|
+
return check.isinstance(message.c, str)
|
|
24
|
+
else:
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
elif isinstance(message, mc.ToolUseMessage):
|
|
28
|
+
return None
|
|
29
|
+
|
|
30
|
+
elif isinstance(message, mc.ToolUseResultMessage):
|
|
31
|
+
return check.isinstance(message.tur.c, str)
|
|
32
|
+
|
|
33
|
+
else:
|
|
34
|
+
raise TypeError(message)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from omlish import lang
|
|
5
|
+
from omlish.formats import json
|
|
6
|
+
|
|
7
|
+
from ... import minichain as mc
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ContentStringifier(lang.Abstract):
|
|
14
|
+
@abc.abstractmethod
|
|
15
|
+
def stringify_content(self, content: 'mc.Content') -> str | None:
|
|
16
|
+
raise NotImplementedError
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ContentStringifierImpl(ContentStringifier):
|
|
20
|
+
def stringify_content(self, content: 'mc.Content') -> str | None:
|
|
21
|
+
if isinstance(content, str):
|
|
22
|
+
return content
|
|
23
|
+
|
|
24
|
+
elif isinstance(content, mc.JsonContent):
|
|
25
|
+
return json.dumps_pretty(content.v)
|
|
26
|
+
|
|
27
|
+
else:
|
|
28
|
+
raise TypeError(content)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class HasContentStringifier(lang.Abstract):
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
*args: ta.Any,
|
|
35
|
+
content_stringifier: ContentStringifier | None = None,
|
|
36
|
+
**kwargs: ta.Any,
|
|
37
|
+
) -> None:
|
|
38
|
+
super().__init__(*args, **kwargs)
|
|
39
|
+
|
|
40
|
+
if content_stringifier is None:
|
|
41
|
+
content_stringifier = ContentStringifierImpl()
|
|
42
|
+
self._content_stringifier = content_stringifier
|
ommlds/cli/inject.py
CHANGED
|
@@ -1,30 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import typing as ta
|
|
2
2
|
|
|
3
|
-
from omdev.home.paths import get_home_paths
|
|
4
3
|
from omlish import inject as inj
|
|
5
4
|
from omlish import lang
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
with lang.auto_proxy_import(globals()):
|
|
9
|
-
from . import
|
|
10
|
-
from .
|
|
11
|
-
from .
|
|
12
|
-
from .sessions import inject as sessions_inj
|
|
13
|
-
from .tools import config as tools_cfg
|
|
14
|
-
from .tools import inject as tools_inj
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
##
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _provide_state_storage() -> 'state.StateStorage':
|
|
21
|
-
state_dir = os.path.join(get_home_paths().state_dir, 'minichain', 'cli')
|
|
22
|
-
if not os.path.exists(state_dir):
|
|
23
|
-
os.makedirs(state_dir, exist_ok=True)
|
|
24
|
-
os.chmod(state_dir, 0o770) # noqa
|
|
25
|
-
|
|
26
|
-
state_file = os.path.join(state_dir, 'state.json')
|
|
27
|
-
return state.JsonFileStateStorage(state_file)
|
|
8
|
+
from . import asyncs
|
|
9
|
+
from .sessions import inject as _sessions
|
|
10
|
+
from .state import inject as _state
|
|
28
11
|
|
|
29
12
|
|
|
30
13
|
##
|
|
@@ -32,23 +15,23 @@ def _provide_state_storage() -> 'state.StateStorage':
|
|
|
32
15
|
|
|
33
16
|
def bind_main(
|
|
34
17
|
*,
|
|
35
|
-
session_cfg:
|
|
36
|
-
tools_config: 'tools_cfg.ToolsConfig',
|
|
37
|
-
enable_backend_strings: bool = False,
|
|
18
|
+
session_cfg: ta.Any,
|
|
38
19
|
) -> inj.Elements:
|
|
39
|
-
els: list[inj.Elemental] = [
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
),
|
|
20
|
+
els: list[inj.Elemental] = []
|
|
21
|
+
|
|
22
|
+
#
|
|
43
23
|
|
|
44
|
-
|
|
24
|
+
els.extend([
|
|
25
|
+
_sessions.bind_sessions(session_cfg),
|
|
45
26
|
|
|
46
|
-
|
|
47
|
-
]
|
|
27
|
+
_state.bind_state(),
|
|
28
|
+
])
|
|
48
29
|
|
|
49
30
|
#
|
|
50
31
|
|
|
51
|
-
els.
|
|
32
|
+
els.extend([
|
|
33
|
+
inj.bind(asyncs.AsyncThreadRunner, to_ctor=asyncs.AnyioAsyncThreadRunner),
|
|
34
|
+
])
|
|
52
35
|
|
|
53
36
|
#
|
|
54
37
|
|
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from .. import asyncs
|
|
4
|
+
from .sync import SyncStringInput
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AsyncStringInput(ta.Protocol):
|
|
11
|
+
def __call__(self) -> ta.Awaitable[str]: ...
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ThreadAsyncStringInput:
|
|
15
|
+
def __init__(self, child: SyncStringInput, runner: asyncs.AsyncThreadRunner) -> None:
|
|
16
|
+
super().__init__()
|
|
17
|
+
|
|
18
|
+
self._child = child
|
|
19
|
+
self._runner = runner
|
|
20
|
+
|
|
21
|
+
async def __call__(self) -> str:
|
|
22
|
+
return await self._runner.run_in_thread(self._child)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class SyncAsyncStringInput:
|
|
26
|
+
def __init__(self, child: SyncStringInput) -> None:
|
|
27
|
+
super().__init__()
|
|
28
|
+
|
|
29
|
+
self._child = child
|
|
30
|
+
|
|
31
|
+
async def __call__(self) -> str:
|
|
32
|
+
return self._child()
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from omlish import check
|
|
5
|
+
from omlish import lang
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
with lang.auto_proxy_import(globals()):
|
|
9
|
+
from omlish.subprocesses import editor
|
|
10
|
+
from omlish.subprocesses import sync as sync_subprocesses
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SyncStringInput(ta.Protocol):
|
|
17
|
+
def __call__(self) -> str: ...
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class InputSyncStringInput:
|
|
21
|
+
DEFAULT_PROMPT: ta.ClassVar[str] = '> '
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
prompt: str | None = None,
|
|
26
|
+
*,
|
|
27
|
+
use_readline: bool | ta.Literal['auto'] = False,
|
|
28
|
+
) -> None:
|
|
29
|
+
super().__init__()
|
|
30
|
+
|
|
31
|
+
if prompt is None:
|
|
32
|
+
prompt = self.DEFAULT_PROMPT
|
|
33
|
+
self._prompt = prompt
|
|
34
|
+
self._use_readline = use_readline
|
|
35
|
+
|
|
36
|
+
self._handled_readline = False
|
|
37
|
+
|
|
38
|
+
def _handle_readline(self) -> None:
|
|
39
|
+
if self._handled_readline:
|
|
40
|
+
return
|
|
41
|
+
self._handled_readline = True
|
|
42
|
+
|
|
43
|
+
if not self._use_readline:
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
if self._use_readline == 'auto':
|
|
47
|
+
if not sys.stdin.isatty():
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
import readline # noqa
|
|
52
|
+
except ImportError:
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
def __call__(self) -> str:
|
|
56
|
+
self._handle_readline()
|
|
57
|
+
return input(self._prompt)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class FileSyncStringInput(InputSyncStringInput):
|
|
61
|
+
def __init__(self, path: str) -> None:
|
|
62
|
+
super().__init__()
|
|
63
|
+
|
|
64
|
+
self._path = check.non_empty_str(path)
|
|
65
|
+
|
|
66
|
+
def __call__(self) -> str:
|
|
67
|
+
with open(self._path) as f:
|
|
68
|
+
return f.read()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class UserEditorSyncStringInput(InputSyncStringInput):
|
|
72
|
+
def __call__(self) -> str:
|
|
73
|
+
if (ec := editor.edit_text_with_user_editor('', sync_subprocesses.subprocesses)) is None:
|
|
74
|
+
raise EOFError
|
|
75
|
+
return ec
|