ommlds 0.0.0.dev463__py3-none-any.whl → 0.0.0.dev465__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.
Potentially problematic release.
This version of ommlds might be problematic. Click here for more details.
- ommlds/.omlish-manifests.json +2 -2
- ommlds/cli/inject.py +14 -32
- ommlds/cli/main.py +34 -59
- ommlds/cli/sessions/{chat2 → chat}/backends/catalog.py +5 -5
- ommlds/cli/sessions/chat/backends/inject.py +37 -0
- ommlds/cli/sessions/chat/backends/injection.py +16 -0
- ommlds/cli/sessions/{chat2 → chat}/backends/types.py +3 -3
- ommlds/cli/sessions/chat/chat/ai/inject.py +78 -0
- ommlds/cli/sessions/chat/chat/ai/injection.py +14 -0
- ommlds/cli/sessions/{chat2 → chat}/chat/ai/rendering.py +13 -10
- ommlds/cli/sessions/chat/chat/ai/services.py +81 -0
- ommlds/cli/sessions/chat/chat/ai/tools.py +44 -0
- ommlds/cli/sessions/{chat2 → chat}/chat/ai/types.py +5 -5
- ommlds/cli/sessions/chat/chat/state/inject.py +40 -0
- ommlds/cli/sessions/{chat2 → chat}/chat/state/inmemory.py +1 -1
- ommlds/cli/sessions/{chat2 → chat}/chat/state/storage.py +2 -2
- ommlds/cli/sessions/{chat2 → chat}/chat/state/types.py +1 -1
- ommlds/cli/sessions/chat/chat/user/inject.py +61 -0
- ommlds/cli/sessions/{chat2 → chat}/chat/user/interactive.py +1 -1
- ommlds/cli/sessions/{chat2 → chat}/chat/user/oneshot.py +1 -1
- ommlds/cli/sessions/{chat2 → chat}/chat/user/types.py +1 -1
- ommlds/cli/sessions/{chat2 → chat}/configs.py +4 -1
- ommlds/cli/sessions/{chat2 → chat}/content/messages.py +6 -2
- ommlds/cli/sessions/{chat2 → chat}/content/strings.py +2 -2
- ommlds/cli/sessions/{chat2 → chat}/driver.py +2 -2
- ommlds/cli/sessions/chat/inject.py +47 -63
- ommlds/cli/sessions/chat/phases/inject.py +27 -0
- ommlds/cli/sessions/chat/phases/injection.py +14 -0
- ommlds/cli/sessions/{chat2/phases.py → chat/phases/manager.py} +2 -28
- ommlds/cli/sessions/chat/phases/types.py +29 -0
- ommlds/cli/sessions/chat/rendering/inject.py +32 -0
- ommlds/cli/sessions/{chat2 → chat}/rendering/markdown.py +2 -2
- ommlds/cli/sessions/{chat2 → chat}/rendering/raw.py +6 -6
- ommlds/cli/sessions/{chat2 → chat}/rendering/types.py +1 -1
- ommlds/cli/sessions/{chat2 → chat}/session.py +1 -1
- ommlds/cli/sessions/{chat2 → chat}/tools/confirmation.py +4 -4
- ommlds/cli/sessions/{chat2 → chat}/tools/execution.py +18 -5
- ommlds/cli/sessions/chat/tools/inject.py +145 -0
- ommlds/cli/sessions/chat/tools/injection.py +29 -0
- ommlds/cli/sessions/chat/tools/rendering.py +58 -0
- ommlds/cli/{tools → sessions/chat/tools}/weather.py +1 -1
- ommlds/cli/sessions/completion/configs.py +21 -0
- ommlds/cli/sessions/completion/inject.py +28 -0
- ommlds/cli/sessions/completion/{completion.py → session.py} +4 -9
- ommlds/cli/sessions/embedding/configs.py +21 -0
- ommlds/cli/sessions/embedding/inject.py +28 -0
- ommlds/cli/sessions/embedding/{embedding.py → session.py} +4 -9
- ommlds/cli/sessions/inject.py +27 -15
- ommlds/cli/state/inject.py +28 -0
- ommlds/minichain/backends/impls/anthropic/chat.py +4 -61
- ommlds/minichain/backends/impls/anthropic/protocol.py +109 -0
- ommlds/minichain/backends/impls/anthropic/stream.py +17 -17
- {ommlds-0.0.0.dev463.dist-info → ommlds-0.0.0.dev465.dist-info}/METADATA +3 -3
- {ommlds-0.0.0.dev463.dist-info → ommlds-0.0.0.dev465.dist-info}/RECORD +69 -60
- ommlds/cli/sessions/chat/base.py +0 -42
- ommlds/cli/sessions/chat/code.py +0 -125
- ommlds/cli/sessions/chat/interactive.py +0 -70
- ommlds/cli/sessions/chat/printing.py +0 -126
- ommlds/cli/sessions/chat/prompt.py +0 -161
- ommlds/cli/sessions/chat/state.py +0 -110
- ommlds/cli/sessions/chat/tools.py +0 -97
- ommlds/cli/sessions/chat2/_inject.py +0 -105
- ommlds/cli/sessions/chat2/chat/ai/services.py +0 -70
- ommlds/cli/sessions/chat2/inject.py +0 -143
- ommlds/cli/tools/config.py +0 -14
- ommlds/cli/tools/inject.py +0 -75
- /ommlds/cli/sessions/{chat2 → chat/backends}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2/backends → chat/chat}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2/chat → chat/chat/ai}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2/chat/ai → chat/chat/state}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2/chat/state → chat/chat/user}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2/chat/user → chat/content}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2/content → chat/phases}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2 → chat}/rendering/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2 → chat}/tools/__init__.py +0 -0
- /ommlds/cli/{tools → state}/__init__.py +0 -0
- /ommlds/cli/{state.py → state/storage.py} +0 -0
- {ommlds-0.0.0.dev463.dist-info → ommlds-0.0.0.dev465.dist-info}/WHEEL +0 -0
- {ommlds-0.0.0.dev463.dist-info → ommlds-0.0.0.dev465.dist-info}/entry_points.txt +0 -0
- {ommlds-0.0.0.dev463.dist-info → ommlds-0.0.0.dev465.dist-info}/licenses/LICENSE +0 -0
- {ommlds-0.0.0.dev463.dist-info → ommlds-0.0.0.dev465.dist-info}/top_level.txt +0 -0
ommlds/.omlish-manifests.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"module": ".minichain.backends.impls.anthropic.chat",
|
|
19
19
|
"attr": null,
|
|
20
20
|
"file": "ommlds/minichain/backends/impls/anthropic/chat.py",
|
|
21
|
-
"line":
|
|
21
|
+
"line": 38,
|
|
22
22
|
"value": {
|
|
23
23
|
"!.minichain.registries.manifests.RegistryManifest": {
|
|
24
24
|
"module": "ommlds.minichain.backends.impls.anthropic.chat",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"module": ".minichain.backends.impls.anthropic.stream",
|
|
64
64
|
"attr": null,
|
|
65
65
|
"file": "ommlds/minichain/backends/impls/anthropic/stream.py",
|
|
66
|
-
"line":
|
|
66
|
+
"line": 35,
|
|
67
67
|
"value": {
|
|
68
68
|
"!.minichain.registries.manifests.RegistryManifest": {
|
|
69
69
|
"module": "ommlds.minichain.backends.impls.anthropic.stream",
|
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 .backends import inject as _backends
|
|
9
|
+
from .sessions import inject as _sessions
|
|
10
|
+
from .state import inject as _state
|
|
28
11
|
|
|
29
12
|
|
|
30
13
|
##
|
|
@@ -32,23 +15,22 @@ def _provide_state_storage() -> 'state.StateStorage':
|
|
|
32
15
|
|
|
33
16
|
def bind_main(
|
|
34
17
|
*,
|
|
35
|
-
session_cfg:
|
|
36
|
-
tools_config: 'tools_cfg.ToolsConfig',
|
|
18
|
+
session_cfg: ta.Any,
|
|
37
19
|
enable_backend_strings: bool = False,
|
|
38
20
|
) -> inj.Elements:
|
|
39
|
-
els: list[inj.Elemental] = [
|
|
40
|
-
backends_inj.bind_backends(
|
|
41
|
-
enable_backend_strings=enable_backend_strings,
|
|
42
|
-
),
|
|
21
|
+
els: list[inj.Elemental] = []
|
|
43
22
|
|
|
44
|
-
|
|
23
|
+
#
|
|
45
24
|
|
|
46
|
-
|
|
47
|
-
|
|
25
|
+
els.extend([
|
|
26
|
+
_backends.bind_backends(
|
|
27
|
+
enable_backend_strings=enable_backend_strings,
|
|
28
|
+
),
|
|
48
29
|
|
|
49
|
-
|
|
30
|
+
_sessions.bind_sessions(session_cfg),
|
|
50
31
|
|
|
51
|
-
|
|
32
|
+
_state.bind_state(),
|
|
33
|
+
])
|
|
52
34
|
|
|
53
35
|
#
|
|
54
36
|
|
ommlds/cli/main.py
CHANGED
|
@@ -24,13 +24,9 @@ from omlish.subprocesses.sync import subprocesses
|
|
|
24
24
|
from .. import minichain as mc
|
|
25
25
|
from .inject import bind_main
|
|
26
26
|
from .sessions.base import Session
|
|
27
|
-
from .sessions.chat.
|
|
28
|
-
from .sessions.
|
|
29
|
-
from .sessions.
|
|
30
|
-
from .sessions.chat2.session import Chat2Session
|
|
31
|
-
from .sessions.completion.completion import CompletionSession
|
|
32
|
-
from .sessions.embedding.embedding import EmbeddingSession
|
|
33
|
-
from .tools.config import ToolsConfig
|
|
27
|
+
from .sessions.chat.configs import ChatConfig
|
|
28
|
+
from .sessions.completion.configs import CompletionConfig
|
|
29
|
+
from .sessions.embedding.configs import EmbeddingConfig
|
|
34
30
|
|
|
35
31
|
|
|
36
32
|
if ta.TYPE_CHECKING:
|
|
@@ -57,6 +53,7 @@ async def _a_main(args: ta.Any = None) -> None:
|
|
|
57
53
|
parser.add_argument('-C', '--completion', action='store_true')
|
|
58
54
|
|
|
59
55
|
parser.add_argument('-n', '--new', action='store_true')
|
|
56
|
+
parser.add_argument('--ephemeral', action='store_true')
|
|
60
57
|
|
|
61
58
|
parser.add_argument('-e', '--editor', action='store_true')
|
|
62
59
|
parser.add_argument('-i', '--interactive', action='store_true')
|
|
@@ -67,8 +64,6 @@ async def _a_main(args: ta.Any = None) -> None:
|
|
|
67
64
|
parser.add_argument('-E', '--embed', action='store_true')
|
|
68
65
|
parser.add_argument('-j', '--image', action='store_true')
|
|
69
66
|
|
|
70
|
-
parser.add_argument('-2', '--two', action='store_true')
|
|
71
|
-
|
|
72
67
|
parser.add_argument('--enable-fs-tools', action='store_true')
|
|
73
68
|
parser.add_argument('--enable-todo-tools', action='store_true')
|
|
74
69
|
parser.add_argument('--enable-unsafe-tools-do-not-use-lol', action='store_true')
|
|
@@ -93,6 +88,7 @@ async def _a_main(args: ta.Any = None) -> None:
|
|
|
93
88
|
elif args.interactive:
|
|
94
89
|
if args.prompt:
|
|
95
90
|
raise ValueError('Must not provide prompt')
|
|
91
|
+
content = None
|
|
96
92
|
|
|
97
93
|
elif args.code:
|
|
98
94
|
if args.prompt:
|
|
@@ -129,77 +125,56 @@ async def _a_main(args: ta.Any = None) -> None:
|
|
|
129
125
|
|
|
130
126
|
#
|
|
131
127
|
|
|
132
|
-
session_cfg:
|
|
128
|
+
session_cfg: ta.Any
|
|
133
129
|
|
|
134
|
-
if args.
|
|
135
|
-
session_cfg =
|
|
136
|
-
backend=args.backend,
|
|
137
|
-
model_name=args.model_name,
|
|
138
|
-
state='ephemeral',
|
|
139
|
-
initial_content=content, # noqa
|
|
140
|
-
# dangerous_no_tool_confirmation=bool(args.dangerous_no_tool_confirmation),
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
elif args.interactive:
|
|
144
|
-
session_cfg = InteractiveChatSession.Config(
|
|
145
|
-
backend=args.backend,
|
|
146
|
-
model_name=args.model_name,
|
|
147
|
-
new=bool(args.new),
|
|
148
|
-
dangerous_no_tool_confirmation=bool(args.dangerous_no_tool_confirmation),
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
elif args.code:
|
|
152
|
-
session_cfg = CodeChatSession.Config(
|
|
153
|
-
backend=args.backend,
|
|
154
|
-
model_name=args.model_name,
|
|
155
|
-
new=bool(args.new),
|
|
156
|
-
dangerous_no_tool_confirmation=bool(args.dangerous_no_tool_confirmation),
|
|
157
|
-
initial_message=content, # noqa
|
|
158
|
-
markdown=bool(args.markdown),
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
elif args.embed:
|
|
162
|
-
session_cfg = EmbeddingSession.Config(
|
|
130
|
+
if args.embed:
|
|
131
|
+
session_cfg = EmbeddingConfig(
|
|
163
132
|
check.not_none(content), # noqa
|
|
164
133
|
backend=args.backend,
|
|
165
134
|
)
|
|
166
135
|
|
|
167
136
|
elif args.completion:
|
|
168
|
-
session_cfg =
|
|
137
|
+
session_cfg = CompletionConfig(
|
|
169
138
|
check.not_none(content), # noqa
|
|
170
139
|
backend=args.backend,
|
|
171
140
|
)
|
|
172
141
|
|
|
173
142
|
else:
|
|
174
|
-
|
|
175
|
-
|
|
143
|
+
system_content: mc.Content | None = None
|
|
144
|
+
if (args.new or args.ephemeral) and args.code:
|
|
145
|
+
from ..minichain.lib.code.prompts import CODE_AGENT_SYSTEM_PROMPT
|
|
146
|
+
system_content = CODE_AGENT_SYSTEM_PROMPT
|
|
147
|
+
|
|
148
|
+
session_cfg = ChatConfig(
|
|
176
149
|
backend=args.backend,
|
|
177
150
|
model_name=args.model_name,
|
|
178
|
-
|
|
179
|
-
|
|
151
|
+
state='ephemeral' if args.ephemeral else 'new' if args.new else 'continue',
|
|
152
|
+
initial_system_content=system_content,
|
|
153
|
+
initial_user_content=content, # noqa
|
|
154
|
+
interactive=bool(args.interactive),
|
|
180
155
|
markdown=bool(args.markdown),
|
|
156
|
+
stream=bool(args.stream),
|
|
157
|
+
enable_tools=(
|
|
158
|
+
args.enable_fs_tools or
|
|
159
|
+
args.enable_todo_tools or
|
|
160
|
+
args.enable_unsafe_tools_do_not_use_lol or
|
|
161
|
+
args.enable_test_weather_tool or
|
|
162
|
+
args.code
|
|
163
|
+
),
|
|
164
|
+
enabled_tools={
|
|
165
|
+
*(['fs'] if args.enable_fs_tools else []),
|
|
166
|
+
*(['todo'] if args.enable_todo_tools else []),
|
|
167
|
+
*(['weather'] if args.enable_test_weather_tool else []),
|
|
168
|
+
# FIXME: enable_unsafe_tools_do_not_use_lol
|
|
169
|
+
},
|
|
181
170
|
dangerous_no_tool_confirmation=bool(args.dangerous_no_tool_confirmation),
|
|
182
171
|
)
|
|
183
172
|
|
|
184
173
|
#
|
|
185
174
|
|
|
186
|
-
tools_config = ToolsConfig(
|
|
187
|
-
enable_fs_tools=args.enable_fs_tools or args.code,
|
|
188
|
-
enable_todo_tools=args.enable_todo_tools or args.code,
|
|
189
|
-
enable_unsafe_tools_do_not_use_lol=args.enable_unsafe_tools_do_not_use_lol,
|
|
190
|
-
enable_test_weather_tool=args.enable_test_weather_tool,
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
#
|
|
194
|
-
|
|
195
175
|
with inj.create_managed_injector(bind_main(
|
|
196
176
|
session_cfg=session_cfg,
|
|
197
|
-
|
|
198
|
-
enable_backend_strings=isinstance(session_cfg, (
|
|
199
|
-
Chat2Session.Config,
|
|
200
|
-
CodeChatSession.Config,
|
|
201
|
-
PromptChatSession.Config,
|
|
202
|
-
)),
|
|
177
|
+
enable_backend_strings=isinstance(session_cfg, ChatConfig),
|
|
203
178
|
)) as injector:
|
|
204
179
|
await injector[Session].run()
|
|
205
180
|
|
|
@@ -20,7 +20,7 @@ class _CatalogBackendProvider(BackendProvider[ServiceT], lang.Abstract):
|
|
|
20
20
|
self,
|
|
21
21
|
*,
|
|
22
22
|
name: BackendName,
|
|
23
|
-
catalog: mc.BackendCatalog,
|
|
23
|
+
catalog: 'mc.BackendCatalog',
|
|
24
24
|
configs: BackendConfigs | None = None,
|
|
25
25
|
) -> None:
|
|
26
26
|
super().__init__()
|
|
@@ -41,16 +41,16 @@ class _CatalogBackendProvider(BackendProvider[ServiceT], lang.Abstract):
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
class CatalogChatChoicesServiceBackendProvider(
|
|
44
|
-
_CatalogBackendProvider[mc.ChatChoicesService],
|
|
44
|
+
_CatalogBackendProvider['mc.ChatChoicesService'],
|
|
45
45
|
ChatChoicesServiceBackendProvider,
|
|
46
46
|
):
|
|
47
|
-
def provide_backend(self) -> ta.AsyncContextManager[mc.ChatChoicesService]:
|
|
47
|
+
def provide_backend(self) -> ta.AsyncContextManager['mc.ChatChoicesService']:
|
|
48
48
|
return self._provide_backend(mc.ChatChoicesService) # type: ignore[type-abstract]
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
class CatalogChatChoicesStreamServiceBackendProvider(
|
|
52
|
-
_CatalogBackendProvider[mc.ChatChoicesStreamService],
|
|
52
|
+
_CatalogBackendProvider['mc.ChatChoicesStreamService'],
|
|
53
53
|
ChatChoicesStreamServiceBackendProvider,
|
|
54
54
|
):
|
|
55
|
-
def provide_backend(self) -> ta.AsyncContextManager[mc.ChatChoicesStreamService]:
|
|
55
|
+
def provide_backend(self) -> ta.AsyncContextManager['mc.ChatChoicesStreamService']:
|
|
56
56
|
return self._provide_backend(mc.ChatChoicesStreamService) # type: ignore[type-abstract]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from omlish import inject as inj
|
|
2
|
+
from omlish import lang
|
|
3
|
+
|
|
4
|
+
from .injection import backend_configs
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
with lang.auto_proxy_import(globals()):
|
|
8
|
+
from . import catalog as _catalog
|
|
9
|
+
from . import types as _types
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def bind_backends(
|
|
16
|
+
*,
|
|
17
|
+
backend: str | None = None,
|
|
18
|
+
) -> inj.Elements:
|
|
19
|
+
els: list[inj.Elemental] = []
|
|
20
|
+
|
|
21
|
+
#
|
|
22
|
+
|
|
23
|
+
els.append(backend_configs().bind_items_provider(singleton=True))
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
|
|
27
|
+
if backend is not None:
|
|
28
|
+
els.append(inj.bind(_types.BackendName, to_const=backend))
|
|
29
|
+
|
|
30
|
+
els.extend([
|
|
31
|
+
inj.bind(_types.ChatChoicesServiceBackendProvider, to_ctor=_catalog.CatalogChatChoicesServiceBackendProvider, singleton=True), # noqa
|
|
32
|
+
inj.bind(_types.ChatChoicesStreamServiceBackendProvider, to_ctor=_catalog.CatalogChatChoicesStreamServiceBackendProvider, singleton=True), # noqa
|
|
33
|
+
])
|
|
34
|
+
|
|
35
|
+
#
|
|
36
|
+
|
|
37
|
+
return inj.as_elements(*els)
|
|
@@ -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)
|
|
@@ -13,7 +13,7 @@ ServiceT = ta.TypeVar('ServiceT', bound=mc.Service)
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
BackendName = ta.NewType('BackendName', str)
|
|
16
|
-
BackendConfigs = ta.NewType('BackendConfigs', ta.Sequence[mc.Config])
|
|
16
|
+
BackendConfigs = ta.NewType('BackendConfigs', ta.Sequence['mc.Config'])
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
##
|
|
@@ -28,9 +28,9 @@ class BackendProvider(lang.Abstract, ta.Generic[ServiceT]):
|
|
|
28
28
|
##
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
class ChatChoicesServiceBackendProvider(BackendProvider[mc.ChatChoicesService], lang.Abstract):
|
|
31
|
+
class ChatChoicesServiceBackendProvider(BackendProvider['mc.ChatChoicesService'], lang.Abstract):
|
|
32
32
|
pass
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
class ChatChoicesStreamServiceBackendProvider(BackendProvider[mc.ChatChoicesStreamService], lang.Abstract):
|
|
35
|
+
class ChatChoicesStreamServiceBackendProvider(BackendProvider['mc.ChatChoicesStreamService'], lang.Abstract):
|
|
36
36
|
pass
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from omlish import inject as inj
|
|
2
|
+
from omlish import lang
|
|
3
|
+
|
|
4
|
+
from ...... import minichain as mc
|
|
5
|
+
from .injection import chat_options_providers
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
with lang.auto_proxy_import(globals()):
|
|
9
|
+
from . import rendering as _rendering
|
|
10
|
+
from . import services as _services
|
|
11
|
+
from . import tools as _tools
|
|
12
|
+
from . import types as _types
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def bind_ai(
|
|
19
|
+
*,
|
|
20
|
+
stream: bool = False,
|
|
21
|
+
silent: bool = False,
|
|
22
|
+
enable_tools: bool = False,
|
|
23
|
+
) -> inj.Elements:
|
|
24
|
+
els: list[inj.Elemental] = []
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
|
|
28
|
+
els.append(chat_options_providers().bind_items_provider(singleton=True))
|
|
29
|
+
|
|
30
|
+
def _provide_chat_choices_options_provider(
|
|
31
|
+
ps: _services.ChatChoicesServiceOptionsProviders,
|
|
32
|
+
) -> _services.ChatChoicesServiceOptionsProvider:
|
|
33
|
+
return _services.ChatChoicesServiceOptionsProvider(lambda: [o for p in ps for o in p()])
|
|
34
|
+
|
|
35
|
+
els.append(inj.bind(_provide_chat_choices_options_provider, singleton=True))
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
|
|
39
|
+
ai_stack = inj.wrapper_binder_helper(_types.AiChatGenerator)
|
|
40
|
+
|
|
41
|
+
if stream:
|
|
42
|
+
stream_ai_stack = inj.wrapper_binder_helper(_types.StreamAiChatGenerator)
|
|
43
|
+
|
|
44
|
+
els.append(stream_ai_stack.push_bind(to_ctor=_services.ChatChoicesStreamServiceStreamAiChatGenerator, singleton=True)) # noqa
|
|
45
|
+
|
|
46
|
+
if not silent:
|
|
47
|
+
els.append(stream_ai_stack.push_bind(to_ctor=_rendering.RenderingStreamAiChatGenerator, singleton=True))
|
|
48
|
+
|
|
49
|
+
els.extend([
|
|
50
|
+
inj.bind(_types.StreamAiChatGenerator, to_key=stream_ai_stack.top),
|
|
51
|
+
ai_stack.push_bind(to_key=_types.StreamAiChatGenerator),
|
|
52
|
+
])
|
|
53
|
+
|
|
54
|
+
else:
|
|
55
|
+
els.append(ai_stack.push_bind(to_ctor=_services.ChatChoicesServiceAiChatGenerator, singleton=True))
|
|
56
|
+
|
|
57
|
+
if not silent:
|
|
58
|
+
els.append(ai_stack.push_bind(to_ctor=_rendering.RenderingAiChatGenerator, singleton=True))
|
|
59
|
+
|
|
60
|
+
if enable_tools:
|
|
61
|
+
els.append(ai_stack.push_bind(to_ctor=_tools.ToolExecutingAiChatGenerator, singleton=True))
|
|
62
|
+
|
|
63
|
+
els.append(inj.bind(_types.AiChatGenerator, to_key=ai_stack.top))
|
|
64
|
+
|
|
65
|
+
#
|
|
66
|
+
|
|
67
|
+
if enable_tools:
|
|
68
|
+
def _provide_tools_chat_choices_options_provider(tc: mc.ToolCatalog) -> _services.ChatChoicesServiceOptionsProvider: # noqa
|
|
69
|
+
return _services.ChatChoicesServiceOptionsProvider(lambda: [
|
|
70
|
+
mc.Tool(tce.spec)
|
|
71
|
+
for tce in tc.by_name.values()
|
|
72
|
+
])
|
|
73
|
+
|
|
74
|
+
els.append(chat_options_providers().bind_item(to_fn=_provide_tools_chat_choices_options_provider, singleton=True)) # noqa
|
|
75
|
+
|
|
76
|
+
#
|
|
77
|
+
|
|
78
|
+
return inj.as_elements(*els)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from omlish import inject as inj
|
|
2
|
+
from omlish import lang
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
with lang.auto_proxy_import(globals()):
|
|
6
|
+
from . import services as _services
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@lang.cached_function
|
|
13
|
+
def chat_options_providers() -> 'inj.ItemsBinderHelper[_services.ChatChoicesServiceOptionsProvider]':
|
|
14
|
+
return inj.items_binder_helper[_services.ChatChoicesServiceOptionsProvider](_services.ChatChoicesServiceOptionsProviders) # noqa
|
|
@@ -4,6 +4,7 @@ from ...... import minichain as mc
|
|
|
4
4
|
from ...content.messages import MessageContentExtractor
|
|
5
5
|
from ...content.messages import MessageContentExtractorImpl
|
|
6
6
|
from ...rendering.types import ContentRendering
|
|
7
|
+
from ...rendering.types import StreamContentRendering
|
|
7
8
|
from .types import AiChatGenerator
|
|
8
9
|
from .types import StreamAiChatGenerator
|
|
9
10
|
|
|
@@ -27,7 +28,7 @@ class RenderingAiChatGenerator(AiChatGenerator):
|
|
|
27
28
|
self._extractor = extractor
|
|
28
29
|
self._renderer = renderer
|
|
29
30
|
|
|
30
|
-
async def get_next_ai_messages(self, chat: mc.Chat) -> mc.
|
|
31
|
+
async def get_next_ai_messages(self, chat: 'mc.Chat') -> 'mc.Chat':
|
|
31
32
|
out = await self._wrapped.get_next_ai_messages(chat)
|
|
32
33
|
|
|
33
34
|
for msg in out:
|
|
@@ -43,7 +44,7 @@ class RenderingStreamAiChatGenerator(StreamAiChatGenerator):
|
|
|
43
44
|
*,
|
|
44
45
|
wrapped: StreamAiChatGenerator,
|
|
45
46
|
extractor: MessageContentExtractor | None = None,
|
|
46
|
-
renderer:
|
|
47
|
+
renderer: StreamContentRendering,
|
|
47
48
|
) -> None:
|
|
48
49
|
super().__init__()
|
|
49
50
|
|
|
@@ -55,13 +56,15 @@ class RenderingStreamAiChatGenerator(StreamAiChatGenerator):
|
|
|
55
56
|
|
|
56
57
|
async def get_next_ai_messages_streamed(
|
|
57
58
|
self,
|
|
58
|
-
chat: mc.Chat,
|
|
59
|
-
delta_callback: ta.Callable[[mc.AiChoiceDelta], ta.Awaitable[None]] | None = None,
|
|
60
|
-
) -> mc.
|
|
61
|
-
async
|
|
62
|
-
|
|
59
|
+
chat: 'mc.Chat',
|
|
60
|
+
delta_callback: ta.Callable[['mc.AiChoiceDelta'], ta.Awaitable[None]] | None = None,
|
|
61
|
+
) -> mc.Chat:
|
|
62
|
+
async with self._renderer.create_context() as renderer:
|
|
63
|
+
async def inner(delta: mc.AiChoiceDelta) -> None:
|
|
64
|
+
if isinstance(delta, mc.ContentAiChoiceDelta):
|
|
65
|
+
await renderer.render_content(delta.c)
|
|
63
66
|
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
if delta_callback is not None:
|
|
68
|
+
await delta_callback(delta)
|
|
66
69
|
|
|
67
|
-
|
|
70
|
+
return await self._wrapped.get_next_ai_messages_streamed(chat, delta_callback=inner)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from omlish import check
|
|
4
|
+
from omlish import lang
|
|
5
|
+
|
|
6
|
+
from ...... import minichain as mc
|
|
7
|
+
from ...backends.types import ChatChoicesServiceBackendProvider
|
|
8
|
+
from ...backends.types import ChatChoicesStreamServiceBackendProvider
|
|
9
|
+
from .types import AiChatGenerator
|
|
10
|
+
from .types import StreamAiChatGenerator
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ChatChoicesServiceOptionsProvider(lang.Func0[ta.Sequence['mc.ChatChoicesOptions']]):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
ChatChoicesServiceOptionsProviders = ta.NewType('ChatChoicesServiceOptionsProviders', ta.Sequence[ChatChoicesServiceOptionsProvider]) # noqa
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ChatChoicesServiceAiChatGenerator(AiChatGenerator):
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
service_provider: ChatChoicesServiceBackendProvider,
|
|
30
|
+
*,
|
|
31
|
+
options: ChatChoicesServiceOptionsProvider | None = None,
|
|
32
|
+
) -> None:
|
|
33
|
+
super().__init__()
|
|
34
|
+
|
|
35
|
+
self._service_provider = service_provider
|
|
36
|
+
self._options = options
|
|
37
|
+
|
|
38
|
+
async def get_next_ai_messages(self, chat: 'mc.Chat') -> 'mc.Chat':
|
|
39
|
+
opts = self._options() if self._options is not None else []
|
|
40
|
+
|
|
41
|
+
async with self._service_provider.provide_backend() as service:
|
|
42
|
+
resp = await service.invoke(mc.ChatChoicesRequest(chat, opts))
|
|
43
|
+
|
|
44
|
+
return check.single(resp.v).ms
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ChatChoicesStreamServiceStreamAiChatGenerator(StreamAiChatGenerator):
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
service_provider: ChatChoicesStreamServiceBackendProvider,
|
|
51
|
+
*,
|
|
52
|
+
options: ChatChoicesServiceOptionsProvider | None = None,
|
|
53
|
+
) -> None:
|
|
54
|
+
super().__init__()
|
|
55
|
+
|
|
56
|
+
self._service_provider = service_provider
|
|
57
|
+
self._options = options
|
|
58
|
+
|
|
59
|
+
async def get_next_ai_messages_streamed(
|
|
60
|
+
self,
|
|
61
|
+
chat: 'mc.Chat',
|
|
62
|
+
delta_callback: ta.Callable[['mc.AiChoiceDelta'], ta.Awaitable[None]] | None = None,
|
|
63
|
+
) -> mc.AiChat:
|
|
64
|
+
opts = self._options() if self._options is not None else []
|
|
65
|
+
|
|
66
|
+
lst: list[str] = []
|
|
67
|
+
|
|
68
|
+
async with self._service_provider.provide_backend() as service:
|
|
69
|
+
async with (await service.invoke(mc.ChatChoicesStreamRequest(chat, opts))).v as st_resp:
|
|
70
|
+
async for o in st_resp:
|
|
71
|
+
choice = check.single(o.choices)
|
|
72
|
+
|
|
73
|
+
for delta in choice.deltas:
|
|
74
|
+
if delta_callback is not None:
|
|
75
|
+
await delta_callback(delta)
|
|
76
|
+
|
|
77
|
+
c = check.isinstance(delta, mc.ContentAiChoiceDelta).c # noqa
|
|
78
|
+
if c is not None:
|
|
79
|
+
lst.append(check.isinstance(c, str))
|
|
80
|
+
|
|
81
|
+
return [mc.AiMessage(''.join(lst))]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from ...... import minichain as mc
|
|
2
|
+
from ...tools.execution import ToolUseExecutor
|
|
3
|
+
from .types import AiChatGenerator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ToolExecutingAiChatGenerator(AiChatGenerator):
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
*,
|
|
13
|
+
wrapped: AiChatGenerator,
|
|
14
|
+
executor: ToolUseExecutor,
|
|
15
|
+
) -> None:
|
|
16
|
+
super().__init__()
|
|
17
|
+
|
|
18
|
+
self._wrapped = wrapped
|
|
19
|
+
self._executor = executor
|
|
20
|
+
|
|
21
|
+
async def get_next_ai_messages(self, chat: 'mc.Chat') -> 'mc.Chat':
|
|
22
|
+
out: list[mc.Message] = []
|
|
23
|
+
|
|
24
|
+
while True:
|
|
25
|
+
new = await self._wrapped.get_next_ai_messages([*chat, *out])
|
|
26
|
+
|
|
27
|
+
out.extend(new)
|
|
28
|
+
|
|
29
|
+
cont = False
|
|
30
|
+
|
|
31
|
+
for msg in new:
|
|
32
|
+
if isinstance(msg, mc.ToolUseMessage):
|
|
33
|
+
trm = await self._executor.execute_tool_use(
|
|
34
|
+
msg.tu,
|
|
35
|
+
# fs_tool_context,
|
|
36
|
+
# todo_tool_context, # noqa
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
out.append(trm)
|
|
40
|
+
|
|
41
|
+
cont = True
|
|
42
|
+
|
|
43
|
+
if not cont:
|
|
44
|
+
return out
|
|
@@ -11,18 +11,18 @@ from ...... import minichain as mc
|
|
|
11
11
|
|
|
12
12
|
class AiChatGenerator(lang.Abstract):
|
|
13
13
|
@abc.abstractmethod
|
|
14
|
-
def get_next_ai_messages(self, chat: mc.Chat) -> ta.Awaitable[mc.
|
|
14
|
+
def get_next_ai_messages(self, chat: 'mc.Chat') -> ta.Awaitable['mc.Chat']:
|
|
15
15
|
raise NotImplementedError
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class StreamAiChatGenerator(AiChatGenerator, lang.Abstract):
|
|
19
|
-
def get_next_ai_messages(self, chat: mc.Chat) -> ta.Awaitable[mc.
|
|
19
|
+
def get_next_ai_messages(self, chat: 'mc.Chat') -> ta.Awaitable['mc.Chat']:
|
|
20
20
|
return self.get_next_ai_messages_streamed(chat)
|
|
21
21
|
|
|
22
22
|
@abc.abstractmethod
|
|
23
23
|
def get_next_ai_messages_streamed(
|
|
24
24
|
self,
|
|
25
|
-
chat: mc.Chat,
|
|
26
|
-
delta_callback: ta.Callable[[mc.AiChoiceDelta], ta.Awaitable[None]] | None = None,
|
|
27
|
-
) -> ta.Awaitable[mc.
|
|
25
|
+
chat: 'mc.Chat',
|
|
26
|
+
delta_callback: ta.Callable[['mc.AiChoiceDelta'], ta.Awaitable[None]] | None = None,
|
|
27
|
+
) -> ta.Awaitable['mc.Chat']:
|
|
28
28
|
raise NotImplementedError
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from omlish import inject as inj
|
|
4
|
+
from omlish import lang
|
|
5
|
+
|
|
6
|
+
from ...phases.injection import phase_callbacks
|
|
7
|
+
from ...phases.types import ChatPhase
|
|
8
|
+
from ...phases.types import ChatPhaseCallback
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
with lang.auto_proxy_import(globals()):
|
|
12
|
+
from . import inmemory as _inmemory
|
|
13
|
+
from . import storage as _storage
|
|
14
|
+
from . import types as _types
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def bind_state(
|
|
21
|
+
*,
|
|
22
|
+
state: ta.Literal['new', 'continue', 'ephemeral'] = 'continue',
|
|
23
|
+
) -> inj.Elements:
|
|
24
|
+
els: list[inj.Elemental] = []
|
|
25
|
+
|
|
26
|
+
if state in ('continue', 'new'):
|
|
27
|
+
els.append(inj.bind(_types.ChatStateManager, to_ctor=_storage.StateStorageChatStateManager, singleton=True))
|
|
28
|
+
|
|
29
|
+
if state == 'new':
|
|
30
|
+
els.append(phase_callbacks().bind_item(to_fn=lang.typed_lambda(cm=_types.ChatStateManager)(
|
|
31
|
+
lambda cm: ChatPhaseCallback(ChatPhase.STARTING, cm.clear_state),
|
|
32
|
+
)))
|
|
33
|
+
|
|
34
|
+
elif state == 'ephemeral':
|
|
35
|
+
els.append(inj.bind(_types.ChatStateManager, to_ctor=_inmemory.InMemoryChatStateManager, singleton=True))
|
|
36
|
+
|
|
37
|
+
else:
|
|
38
|
+
raise TypeError(state)
|
|
39
|
+
|
|
40
|
+
return inj.as_elements(*els)
|