ommlds 0.0.0.dev489__py3-none-any.whl → 0.0.0.dev491__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 +3 -3
- ommlds/README.md +11 -0
- ommlds/__about__.py +1 -1
- ommlds/backends/ollama/_dataclasses.py +53 -23
- ommlds/backends/ollama/protocol.py +3 -0
- ommlds/cli/_dataclasses.py +835 -356
- ommlds/cli/main.py +80 -41
- ommlds/cli/rendering/types.py +6 -0
- ommlds/cli/sessions/chat/configs.py +4 -12
- ommlds/cli/sessions/chat/{chat → drivers}/ai/configs.py +3 -1
- ommlds/cli/sessions/chat/drivers/ai/events.py +57 -0
- ommlds/cli/sessions/chat/{chat → drivers}/ai/inject.py +10 -3
- ommlds/cli/sessions/chat/{chat → drivers}/ai/rendering.py +1 -1
- ommlds/cli/sessions/chat/{chat → drivers}/ai/services.py +1 -1
- ommlds/cli/sessions/chat/{chat → drivers}/ai/tools.py +1 -1
- ommlds/cli/sessions/chat/{chat → drivers}/ai/types.py +9 -0
- ommlds/cli/sessions/chat/drivers/configs.py +25 -0
- ommlds/cli/sessions/chat/drivers/driver.py +49 -0
- ommlds/cli/sessions/chat/drivers/events/inject.py +27 -0
- ommlds/cli/sessions/chat/drivers/events/injection.py +14 -0
- ommlds/cli/sessions/chat/drivers/events/manager.py +16 -0
- ommlds/cli/sessions/chat/drivers/events/types.py +38 -0
- ommlds/cli/sessions/chat/drivers/inject.py +69 -0
- ommlds/cli/sessions/chat/{chat → drivers}/state/inject.py +3 -3
- ommlds/cli/sessions/chat/{chat → drivers}/state/types.py +1 -1
- ommlds/cli/sessions/chat/{tools → drivers/tools}/configs.py +2 -2
- ommlds/cli/sessions/chat/drivers/tools/confirmation.py +44 -0
- ommlds/cli/sessions/chat/{tools → drivers/tools}/execution.py +3 -4
- ommlds/cli/sessions/chat/{tools → drivers/tools}/fs/inject.py +3 -3
- ommlds/cli/sessions/chat/{tools → drivers/tools}/inject.py +4 -12
- ommlds/cli/sessions/chat/{tools → drivers/tools}/injection.py +1 -1
- ommlds/cli/sessions/chat/{tools → drivers/tools}/rendering.py +3 -3
- ommlds/cli/sessions/chat/{tools → drivers/tools}/todo/inject.py +3 -3
- ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/tools.py +1 -1
- ommlds/cli/sessions/chat/drivers/types.py +10 -0
- ommlds/cli/sessions/chat/{chat → drivers}/user/configs.py +0 -2
- ommlds/cli/sessions/chat/drivers/user/inject.py +40 -0
- ommlds/cli/sessions/chat/inject.py +4 -32
- ommlds/cli/sessions/chat/interfaces/bare/inject.py +61 -0
- ommlds/cli/sessions/chat/interfaces/bare/interactive.py +41 -0
- ommlds/cli/sessions/chat/{interface/bare/interface.py → interfaces/bare/oneshot.py} +5 -3
- ommlds/cli/sessions/chat/{tools/confirmation.py → interfaces/bare/tools.py} +3 -22
- ommlds/cli/sessions/chat/{interface → interfaces}/bare/user.py +1 -1
- ommlds/cli/sessions/chat/{interface → interfaces}/configs.py +8 -0
- ommlds/cli/sessions/chat/interfaces/textual/__init__.py +0 -0
- ommlds/cli/sessions/chat/interfaces/textual/app.py +217 -0
- ommlds/cli/sessions/chat/interfaces/textual/inject.py +67 -0
- ommlds/cli/sessions/chat/{interface → interfaces}/textual/interface.py +0 -3
- ommlds/cli/sessions/chat/interfaces/textual/styles/__init__.py +29 -0
- ommlds/cli/sessions/chat/interfaces/textual/styles/input.tcss +51 -0
- ommlds/cli/sessions/chat/interfaces/textual/styles/markdown.tcss +7 -0
- ommlds/cli/sessions/chat/interfaces/textual/styles/messages.tcss +104 -0
- ommlds/cli/sessions/chat/interfaces/textual/widgets/__init__.py +0 -0
- ommlds/cli/sessions/chat/interfaces/textual/widgets/input.py +36 -0
- ommlds/cli/sessions/chat/interfaces/textual/widgets/messages.py +114 -0
- ommlds/cli/sessions/chat/session.py +1 -1
- ommlds/minichain/backends/impls/ollama/chat.py +24 -56
- ommlds/minichain/backends/impls/ollama/protocol.py +144 -0
- ommlds/nanochat/rustbpe/README.md +9 -0
- {ommlds-0.0.0.dev489.dist-info → ommlds-0.0.0.dev491.dist-info}/METADATA +6 -6
- {ommlds-0.0.0.dev489.dist-info → ommlds-0.0.0.dev491.dist-info}/RECORD +91 -73
- ommlds/cli/sessions/chat/chat/user/inject.py +0 -52
- ommlds/cli/sessions/chat/chat/user/oneshot.py +0 -25
- ommlds/cli/sessions/chat/chat/user/types.py +0 -15
- ommlds/cli/sessions/chat/driver.py +0 -43
- ommlds/cli/sessions/chat/interface/bare/inject.py +0 -32
- ommlds/cli/sessions/chat/interface/textual/app.py +0 -191
- ommlds/cli/sessions/chat/interface/textual/inject.py +0 -27
- ommlds/cli/sessions/chat/interface/textual/user.py +0 -20
- /ommlds/cli/sessions/chat/{chat → drivers}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{chat → drivers}/ai/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{chat → drivers}/ai/injection.py +0 -0
- /ommlds/cli/sessions/chat/{chat/state → drivers/events}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{chat/user → drivers/phases}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{phases → drivers/phases}/inject.py +0 -0
- /ommlds/cli/sessions/chat/{phases → drivers/phases}/injection.py +0 -0
- /ommlds/cli/sessions/chat/{phases → drivers/phases}/manager.py +0 -0
- /ommlds/cli/sessions/chat/{phases → drivers/phases}/types.py +0 -0
- /ommlds/cli/sessions/chat/{interface → drivers/state}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{chat → drivers}/state/configs.py +0 -0
- /ommlds/cli/sessions/chat/{chat → drivers}/state/inmemory.py +0 -0
- /ommlds/cli/sessions/chat/{chat → drivers}/state/storage.py +0 -0
- /ommlds/cli/sessions/chat/{interface/bare → drivers/tools}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{interface/textual → drivers/tools/fs}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{tools → drivers/tools}/fs/configs.py +0 -0
- /ommlds/cli/sessions/chat/{phases → drivers/tools/todo}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{tools → drivers/tools}/todo/configs.py +0 -0
- /ommlds/cli/sessions/chat/{tools → drivers/tools/weather}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/configs.py +0 -0
- /ommlds/cli/sessions/chat/{tools → drivers/tools}/weather/inject.py +0 -0
- /ommlds/cli/sessions/chat/{tools/fs → drivers/user}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{tools/todo → interfaces}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{tools/weather → interfaces/bare}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{interface → interfaces}/base.py +0 -0
- /ommlds/cli/sessions/chat/{interface → interfaces}/inject.py +0 -0
- {ommlds-0.0.0.dev489.dist-info → ommlds-0.0.0.dev491.dist-info}/WHEEL +0 -0
- {ommlds-0.0.0.dev489.dist-info → ommlds-0.0.0.dev491.dist-info}/entry_points.txt +0 -0
- {ommlds-0.0.0.dev489.dist-info → ommlds-0.0.0.dev491.dist-info}/licenses/LICENSE +0 -0
- {ommlds-0.0.0.dev489.dist-info → ommlds-0.0.0.dev491.dist-info}/top_level.txt +0 -0
ommlds/cli/main.py
CHANGED
|
@@ -69,9 +69,12 @@ class ChatProfile(Profile):
|
|
|
69
69
|
def configure_backend(self, cfg: ChatConfig) -> ChatConfig:
|
|
70
70
|
return dc.replace(
|
|
71
71
|
cfg,
|
|
72
|
-
|
|
73
|
-
cfg.
|
|
74
|
-
backend=
|
|
72
|
+
driver=dc.replace(
|
|
73
|
+
cfg.driver,
|
|
74
|
+
backend=dc.replace(
|
|
75
|
+
cfg.driver.backend,
|
|
76
|
+
backend=self._args.backend,
|
|
77
|
+
),
|
|
75
78
|
),
|
|
76
79
|
)
|
|
77
80
|
|
|
@@ -89,17 +92,28 @@ class ChatProfile(Profile):
|
|
|
89
92
|
check.arg(not self._args.message)
|
|
90
93
|
raise NotImplementedError
|
|
91
94
|
|
|
92
|
-
if self._args.
|
|
95
|
+
if self._args.textual:
|
|
93
96
|
cfg = dc.replace(
|
|
94
97
|
cfg,
|
|
95
98
|
interface=dc.replace(
|
|
96
99
|
cfg.interface,
|
|
97
|
-
|
|
98
|
-
use_textual=self._args.textual,
|
|
100
|
+
use_textual=True,
|
|
99
101
|
),
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
else:
|
|
105
|
+
cfg = dc.replace(
|
|
106
|
+
cfg,
|
|
107
|
+
driver=dc.replace(
|
|
108
|
+
cfg.driver,
|
|
109
|
+
ai=dc.replace(
|
|
110
|
+
cfg.driver.ai,
|
|
111
|
+
verbose=True,
|
|
112
|
+
),
|
|
113
|
+
),
|
|
114
|
+
interface=dc.replace(
|
|
115
|
+
cfg.interface,
|
|
116
|
+
interactive=self._args.interactive,
|
|
103
117
|
),
|
|
104
118
|
)
|
|
105
119
|
|
|
@@ -112,16 +126,19 @@ class ChatProfile(Profile):
|
|
|
112
126
|
]
|
|
113
127
|
|
|
114
128
|
def configure_input(self, cfg: ChatConfig) -> ChatConfig:
|
|
115
|
-
if self._args.interactive:
|
|
129
|
+
if self._args.interactive or self._args.textual:
|
|
116
130
|
check.arg(not self._args.message)
|
|
117
131
|
|
|
118
132
|
elif self._args.message:
|
|
119
133
|
# TODO: '-' -> stdin
|
|
120
134
|
cfg = dc.replace(
|
|
121
135
|
cfg,
|
|
122
|
-
|
|
123
|
-
cfg.
|
|
124
|
-
|
|
136
|
+
driver=dc.replace(
|
|
137
|
+
cfg.driver,
|
|
138
|
+
user=dc.replace(
|
|
139
|
+
cfg.driver.user,
|
|
140
|
+
initial_user_content=' '.join(self._args.message),
|
|
141
|
+
),
|
|
125
142
|
),
|
|
126
143
|
)
|
|
127
144
|
|
|
@@ -140,9 +157,12 @@ class ChatProfile(Profile):
|
|
|
140
157
|
def configure_state(self, cfg: ChatConfig) -> ChatConfig:
|
|
141
158
|
return dc.replace(
|
|
142
159
|
cfg,
|
|
143
|
-
|
|
144
|
-
cfg.
|
|
145
|
-
state=
|
|
160
|
+
driver=dc.replace(
|
|
161
|
+
cfg.driver,
|
|
162
|
+
state=dc.replace(
|
|
163
|
+
cfg.driver.state,
|
|
164
|
+
state='ephemeral' if self._args.ephemeral else 'new' if self._args.new else 'continue',
|
|
165
|
+
),
|
|
146
166
|
),
|
|
147
167
|
)
|
|
148
168
|
|
|
@@ -156,9 +176,12 @@ class ChatProfile(Profile):
|
|
|
156
176
|
def configure_output(self, cfg: ChatConfig) -> ChatConfig:
|
|
157
177
|
return dc.replace(
|
|
158
178
|
cfg,
|
|
159
|
-
|
|
160
|
-
cfg.
|
|
161
|
-
|
|
179
|
+
driver=dc.replace(
|
|
180
|
+
cfg.driver,
|
|
181
|
+
ai=dc.replace(
|
|
182
|
+
cfg.driver.ai,
|
|
183
|
+
stream=bool(self._args.stream),
|
|
184
|
+
),
|
|
162
185
|
),
|
|
163
186
|
rendering=dc.replace(
|
|
164
187
|
cfg.rendering,
|
|
@@ -176,26 +199,36 @@ class ChatProfile(Profile):
|
|
|
176
199
|
]
|
|
177
200
|
|
|
178
201
|
def configure_tools(self, cfg: ChatConfig) -> ChatConfig:
|
|
202
|
+
if not (
|
|
203
|
+
self._args.enable_fs_tools or
|
|
204
|
+
self._args.enable_todo_tools or
|
|
205
|
+
# self._args.enable_unsafe_tools_do_not_use_lol or
|
|
206
|
+
self._args.enable_test_weather_tool or
|
|
207
|
+
self._args.code
|
|
208
|
+
):
|
|
209
|
+
return cfg
|
|
210
|
+
|
|
179
211
|
return dc.replace(
|
|
180
212
|
cfg,
|
|
181
|
-
|
|
182
|
-
cfg.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
213
|
+
driver=dc.replace(
|
|
214
|
+
cfg.driver,
|
|
215
|
+
ai=dc.replace(
|
|
216
|
+
cfg.driver.ai,
|
|
217
|
+
enable_tools=True,
|
|
218
|
+
),
|
|
219
|
+
tools=dc.replace(
|
|
220
|
+
cfg.driver.tools,
|
|
221
|
+
enabled_tools={ # noqa
|
|
222
|
+
*(cfg.driver.tools.enabled_tools or []),
|
|
223
|
+
*(['fs'] if self._args.enable_fs_tools else []),
|
|
224
|
+
*(['todo'] if self._args.enable_todo_tools else []),
|
|
225
|
+
*(['weather'] if self._args.enable_test_weather_tool else []),
|
|
226
|
+
},
|
|
189
227
|
),
|
|
190
228
|
),
|
|
191
|
-
|
|
192
|
-
cfg.
|
|
193
|
-
|
|
194
|
-
*(cfg.tools.enabled_tools or []),
|
|
195
|
-
*(['fs'] if self._args.enable_fs_tools else []),
|
|
196
|
-
*(['todo'] if self._args.enable_todo_tools else []),
|
|
197
|
-
*(['weather'] if self._args.enable_test_weather_tool else []),
|
|
198
|
-
},
|
|
229
|
+
interface=dc.replace(
|
|
230
|
+
cfg.interface,
|
|
231
|
+
enable_tools=True,
|
|
199
232
|
),
|
|
200
233
|
)
|
|
201
234
|
|
|
@@ -211,9 +244,12 @@ class ChatProfile(Profile):
|
|
|
211
244
|
|
|
212
245
|
cfg = dc.replace(
|
|
213
246
|
cfg,
|
|
214
|
-
|
|
215
|
-
cfg.
|
|
216
|
-
|
|
247
|
+
driver=dc.replace(
|
|
248
|
+
cfg.driver,
|
|
249
|
+
ai=dc.replace(
|
|
250
|
+
cfg.driver.ai,
|
|
251
|
+
enable_tools=True,
|
|
252
|
+
),
|
|
217
253
|
),
|
|
218
254
|
)
|
|
219
255
|
|
|
@@ -223,9 +259,12 @@ class ChatProfile(Profile):
|
|
|
223
259
|
|
|
224
260
|
cfg = dc.replace(
|
|
225
261
|
cfg,
|
|
226
|
-
|
|
227
|
-
cfg.
|
|
228
|
-
|
|
262
|
+
driver=dc.replace(
|
|
263
|
+
cfg.driver,
|
|
264
|
+
user=dc.replace(
|
|
265
|
+
cfg.driver.user,
|
|
266
|
+
initial_system_content=system_content,
|
|
267
|
+
),
|
|
229
268
|
),
|
|
230
269
|
)
|
|
231
270
|
|
ommlds/cli/rendering/types.py
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
from omlish import dataclasses as dc
|
|
2
2
|
|
|
3
|
-
from ...backends.configs import BackendConfig
|
|
4
3
|
from ...rendering.configs import RenderingConfig
|
|
5
|
-
from .
|
|
6
|
-
from .
|
|
7
|
-
from .chat.user.configs import UserConfig
|
|
8
|
-
from .interface.configs import InterfaceConfig
|
|
9
|
-
from .tools.configs import ToolsConfig
|
|
4
|
+
from .drivers.configs import DriverConfig
|
|
5
|
+
from .interfaces.configs import InterfaceConfig
|
|
10
6
|
|
|
11
7
|
|
|
12
8
|
##
|
|
@@ -20,10 +16,6 @@ DEFAULT_BACKEND = 'openai'
|
|
|
20
16
|
|
|
21
17
|
@dc.dataclass(frozen=True, kw_only=True)
|
|
22
18
|
class ChatConfig:
|
|
23
|
-
|
|
24
|
-
ai: AiConfig = AiConfig()
|
|
25
|
-
state: StateConfig = StateConfig()
|
|
26
|
-
user: UserConfig = UserConfig()
|
|
27
|
-
rendering: RenderingConfig = RenderingConfig()
|
|
19
|
+
driver: DriverConfig = DriverConfig()
|
|
28
20
|
interface: InterfaceConfig = InterfaceConfig()
|
|
29
|
-
|
|
21
|
+
rendering: RenderingConfig = RenderingConfig()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from ...... import minichain as mc
|
|
4
|
+
from ..events.manager import ChatEventsManager
|
|
5
|
+
from ..events.types import AiDeltaChatEvent
|
|
6
|
+
from ..events.types import AiMessagesChatEvent
|
|
7
|
+
from .types import AiChatGenerator
|
|
8
|
+
from .types import StreamAiChatGenerator
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class EventEmittingAiChatGenerator(AiChatGenerator):
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
*,
|
|
18
|
+
wrapped: AiChatGenerator,
|
|
19
|
+
events: ChatEventsManager,
|
|
20
|
+
) -> None:
|
|
21
|
+
super().__init__()
|
|
22
|
+
|
|
23
|
+
self._wrapped = wrapped
|
|
24
|
+
self._events = events
|
|
25
|
+
|
|
26
|
+
async def get_next_ai_messages(self, chat: 'mc.Chat') -> 'mc.Chat':
|
|
27
|
+
out = await self._wrapped.get_next_ai_messages(chat)
|
|
28
|
+
|
|
29
|
+
await self._events.emit_event(AiMessagesChatEvent(out))
|
|
30
|
+
|
|
31
|
+
return out
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class EventEmittingStreamAiChatGenerator(StreamAiChatGenerator):
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
*,
|
|
38
|
+
wrapped: StreamAiChatGenerator,
|
|
39
|
+
events: ChatEventsManager,
|
|
40
|
+
) -> None:
|
|
41
|
+
super().__init__()
|
|
42
|
+
|
|
43
|
+
self._wrapped = wrapped
|
|
44
|
+
self._events = events
|
|
45
|
+
|
|
46
|
+
async def get_next_ai_messages_streamed(
|
|
47
|
+
self,
|
|
48
|
+
chat: 'mc.Chat',
|
|
49
|
+
delta_callback: ta.Callable[['mc.AiDelta'], ta.Awaitable[None]] | None = None,
|
|
50
|
+
) -> 'mc.Chat':
|
|
51
|
+
async def inner(delta: mc.AiDelta) -> None:
|
|
52
|
+
await self._events.emit_event(AiDeltaChatEvent(delta))
|
|
53
|
+
|
|
54
|
+
if delta_callback is not None:
|
|
55
|
+
await delta_callback(delta)
|
|
56
|
+
|
|
57
|
+
return await self._wrapped.get_next_ai_messages_streamed(chat, delta_callback=inner)
|
|
@@ -7,6 +7,7 @@ from .injection import chat_options_providers
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
with lang.auto_proxy_import(globals()):
|
|
10
|
+
from . import events as _events
|
|
10
11
|
from . import rendering as _rendering
|
|
11
12
|
from . import services as _services
|
|
12
13
|
from . import tools as _tools
|
|
@@ -39,9 +40,11 @@ def bind_ai(cfg: AiConfig = AiConfig()) -> inj.Elements:
|
|
|
39
40
|
|
|
40
41
|
els.append(stream_ai_stack.push_bind(to_ctor=_services.ChatChoicesStreamServiceStreamAiChatGenerator, singleton=True)) # noqa
|
|
41
42
|
|
|
42
|
-
if
|
|
43
|
+
if cfg.verbose:
|
|
43
44
|
els.append(stream_ai_stack.push_bind(to_ctor=_rendering.RenderingStreamAiChatGenerator, singleton=True))
|
|
44
45
|
|
|
46
|
+
els.append(stream_ai_stack.push_bind(to_ctor=_events.EventEmittingStreamAiChatGenerator, singleton=True))
|
|
47
|
+
|
|
45
48
|
els.extend([
|
|
46
49
|
inj.bind(_types.StreamAiChatGenerator, to_key=stream_ai_stack.top),
|
|
47
50
|
ai_stack.push_bind(to_key=_types.StreamAiChatGenerator),
|
|
@@ -50,9 +53,11 @@ def bind_ai(cfg: AiConfig = AiConfig()) -> inj.Elements:
|
|
|
50
53
|
else:
|
|
51
54
|
els.append(ai_stack.push_bind(to_ctor=_services.ChatChoicesServiceAiChatGenerator, singleton=True))
|
|
52
55
|
|
|
53
|
-
if
|
|
56
|
+
if cfg.verbose:
|
|
54
57
|
els.append(ai_stack.push_bind(to_ctor=_rendering.RenderingAiChatGenerator, singleton=True))
|
|
55
58
|
|
|
59
|
+
els.append(ai_stack.push_bind(to_ctor=_events.EventEmittingAiChatGenerator, singleton=True))
|
|
60
|
+
|
|
56
61
|
if cfg.enable_tools:
|
|
57
62
|
els.append(ai_stack.push_bind(to_ctor=_tools.ToolExecutingAiChatGenerator, singleton=True))
|
|
58
63
|
|
|
@@ -61,7 +66,9 @@ def bind_ai(cfg: AiConfig = AiConfig()) -> inj.Elements:
|
|
|
61
66
|
#
|
|
62
67
|
|
|
63
68
|
if cfg.enable_tools:
|
|
64
|
-
def _provide_tools_chat_choices_options_provider(
|
|
69
|
+
def _provide_tools_chat_choices_options_provider(
|
|
70
|
+
tc: mc.ToolCatalog,
|
|
71
|
+
) -> _services.ChatChoicesServiceOptionsProvider:
|
|
65
72
|
return _services.ChatChoicesServiceOptionsProvider(lambda: [
|
|
66
73
|
mc.Tool(tce.spec)
|
|
67
74
|
for tce in tc.by_name.values()
|
|
@@ -58,7 +58,7 @@ class RenderingStreamAiChatGenerator(StreamAiChatGenerator):
|
|
|
58
58
|
self,
|
|
59
59
|
chat: 'mc.Chat',
|
|
60
60
|
delta_callback: ta.Callable[['mc.AiDelta'], ta.Awaitable[None]] | None = None,
|
|
61
|
-
) -> mc.Chat:
|
|
61
|
+
) -> 'mc.Chat':
|
|
62
62
|
async with self._renderer.create_context() as renderer:
|
|
63
63
|
async def inner(delta: mc.AiDelta) -> None:
|
|
64
64
|
if isinstance(delta, mc.ContentAiDelta):
|
|
@@ -60,7 +60,7 @@ class ChatChoicesStreamServiceStreamAiChatGenerator(StreamAiChatGenerator):
|
|
|
60
60
|
self,
|
|
61
61
|
chat: 'mc.Chat',
|
|
62
62
|
delta_callback: ta.Callable[['mc.AiDelta'], ta.Awaitable[None]] | None = None,
|
|
63
|
-
) -> mc.AiChat:
|
|
63
|
+
) -> 'mc.AiChat':
|
|
64
64
|
opts = self._options() if self._options is not None else []
|
|
65
65
|
|
|
66
66
|
async with self._service_provider.provide_backend() as service:
|
|
@@ -26,3 +26,12 @@ class StreamAiChatGenerator(AiChatGenerator, lang.Abstract):
|
|
|
26
26
|
delta_callback: ta.Callable[['mc.AiDelta'], ta.Awaitable[None]] | None = None,
|
|
27
27
|
) -> ta.Awaitable['mc.Chat']:
|
|
28
28
|
raise NotImplementedError
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class AiChatOutput(lang.Abstract):
|
|
35
|
+
@abc.abstractmethod
|
|
36
|
+
def output_ai_chat(self, chat: 'mc.Chat') -> ta.Awaitable[None]:
|
|
37
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from omlish import dataclasses as dc
|
|
2
|
+
|
|
3
|
+
from ....backends.configs import BackendConfig
|
|
4
|
+
from .ai.configs import AiConfig
|
|
5
|
+
from .state.configs import StateConfig
|
|
6
|
+
from .tools.configs import ToolsConfig
|
|
7
|
+
from .user.configs import UserConfig
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
DEFAULT_BACKEND = 'openai'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
|
20
|
+
class DriverConfig:
|
|
21
|
+
ai: AiConfig = AiConfig()
|
|
22
|
+
backend: BackendConfig = BackendConfig()
|
|
23
|
+
state: StateConfig = StateConfig()
|
|
24
|
+
tools: ToolsConfig = ToolsConfig()
|
|
25
|
+
user: UserConfig = UserConfig()
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- lifecycles
|
|
4
|
+
- StreamService
|
|
5
|
+
"""
|
|
6
|
+
from ..... import minichain as mc
|
|
7
|
+
from .ai.types import AiChatGenerator
|
|
8
|
+
from .events.manager import ChatEventsManager
|
|
9
|
+
from .events.types import UserMessagesChatEvent
|
|
10
|
+
from .phases.manager import ChatPhaseManager
|
|
11
|
+
from .phases.types import ChatPhase
|
|
12
|
+
from .state.types import ChatStateManager
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ChatDriver:
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
*,
|
|
22
|
+
phases: ChatPhaseManager,
|
|
23
|
+
ai_chat_generator: AiChatGenerator,
|
|
24
|
+
chat_state_manager: ChatStateManager,
|
|
25
|
+
events: ChatEventsManager,
|
|
26
|
+
) -> None:
|
|
27
|
+
super().__init__()
|
|
28
|
+
|
|
29
|
+
self._phases = phases
|
|
30
|
+
self._ai_chat_generator = ai_chat_generator
|
|
31
|
+
self._chat_state_manager = chat_state_manager
|
|
32
|
+
self._events = events
|
|
33
|
+
|
|
34
|
+
async def start(self) -> None:
|
|
35
|
+
await self._phases.set_phase(ChatPhase.STARTING)
|
|
36
|
+
await self._phases.set_phase(ChatPhase.STARTED)
|
|
37
|
+
|
|
38
|
+
async def stop(self) -> None:
|
|
39
|
+
await self._phases.set_phase(ChatPhase.STOPPING)
|
|
40
|
+
await self._phases.set_phase(ChatPhase.STOPPED)
|
|
41
|
+
|
|
42
|
+
async def send_user_messages(self, next_user_chat: 'mc.UserChat') -> None:
|
|
43
|
+
await self._events.emit_event(UserMessagesChatEvent(next_user_chat))
|
|
44
|
+
|
|
45
|
+
prev_user_chat = (await self._chat_state_manager.get_state()).chat
|
|
46
|
+
|
|
47
|
+
next_ai_chat = await self._ai_chat_generator.get_next_ai_messages([*prev_user_chat, *next_user_chat])
|
|
48
|
+
|
|
49
|
+
await self._chat_state_manager.extend_chat([*next_user_chat, *next_ai_chat])
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from omlish import inject as inj
|
|
2
|
+
from omlish import lang
|
|
3
|
+
|
|
4
|
+
from .injection import event_callbacks
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
with lang.auto_proxy_import(globals()):
|
|
8
|
+
from . import manager as _manager
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def bind_events() -> inj.Elements:
|
|
15
|
+
els: list[inj.Elemental] = []
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
els.append(event_callbacks().bind_items_provider(singleton=True))
|
|
20
|
+
|
|
21
|
+
#
|
|
22
|
+
|
|
23
|
+
els.append(inj.bind(_manager.ChatEventsManager, singleton=True))
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
|
|
27
|
+
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 types as _types
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@lang.cached_function
|
|
13
|
+
def event_callbacks() -> 'inj.ItemsBinderHelper[_types.ChatEventCallback]':
|
|
14
|
+
return inj.items_binder_helper[_types.ChatEventCallback](_types.ChatEventCallbacks)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from .types import ChatEvent
|
|
2
|
+
from .types import ChatEventCallbacks
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ChatEventsManager:
|
|
9
|
+
def __init__(self, callbacks: ChatEventCallbacks) -> None:
|
|
10
|
+
super().__init__()
|
|
11
|
+
|
|
12
|
+
self._callbacks = callbacks
|
|
13
|
+
|
|
14
|
+
async def emit_event(self, event: ChatEvent) -> None:
|
|
15
|
+
for cb in self._callbacks:
|
|
16
|
+
await cb(event)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from omlish import dataclasses as dc
|
|
4
|
+
from omlish import lang
|
|
5
|
+
|
|
6
|
+
from ...... import minichain as mc
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ChatEvent(lang.Abstract, lang.Sealed):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ChatEventCallback(lang.Func1[ChatEvent, ta.Awaitable[None]]):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
ChatEventCallbacks = ta.NewType('ChatEventCallbacks', ta.Sequence[ChatEventCallback])
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dc.dataclass(frozen=True)
|
|
27
|
+
class UserMessagesChatEvent(ChatEvent, lang.Final):
|
|
28
|
+
chat: 'mc.UserChat'
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dc.dataclass(frozen=True)
|
|
32
|
+
class AiMessagesChatEvent(ChatEvent, lang.Final):
|
|
33
|
+
chat: 'mc.Chat'
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dc.dataclass(frozen=True)
|
|
37
|
+
class AiDeltaChatEvent(ChatEvent, lang.Final):
|
|
38
|
+
delta: 'mc.AiDelta'
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- private + expose(ChatDriver)
|
|
4
|
+
"""
|
|
5
|
+
import uuid
|
|
6
|
+
|
|
7
|
+
from omlish import inject as inj
|
|
8
|
+
from omlish import lang
|
|
9
|
+
|
|
10
|
+
from ....backends.types import DefaultBackendName
|
|
11
|
+
from .configs import DEFAULT_BACKEND
|
|
12
|
+
from .configs import DriverConfig
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
with lang.auto_proxy_import(globals()):
|
|
16
|
+
from ....backends import inject as _backends
|
|
17
|
+
from . import driver as _driver
|
|
18
|
+
from . import types as _types
|
|
19
|
+
from .ai import inject as _ai
|
|
20
|
+
from .events import inject as _events
|
|
21
|
+
from .phases import inject as _phases
|
|
22
|
+
from .state import inject as _state
|
|
23
|
+
from .tools import inject as _tools
|
|
24
|
+
from .user import inject as _user
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def bind_driver(cfg: DriverConfig) -> inj.Elements:
|
|
31
|
+
els: list[inj.Elemental] = []
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
|
|
35
|
+
els.extend([
|
|
36
|
+
_backends.bind_backends(cfg.backend),
|
|
37
|
+
|
|
38
|
+
_ai.bind_ai(cfg.ai),
|
|
39
|
+
|
|
40
|
+
_events.bind_events(),
|
|
41
|
+
|
|
42
|
+
_phases.bind_phases(),
|
|
43
|
+
|
|
44
|
+
_state.bind_state(cfg.state),
|
|
45
|
+
|
|
46
|
+
_tools.bind_tools(cfg.tools),
|
|
47
|
+
|
|
48
|
+
_user.bind_user(cfg.user),
|
|
49
|
+
])
|
|
50
|
+
|
|
51
|
+
#
|
|
52
|
+
|
|
53
|
+
els.extend([
|
|
54
|
+
inj.bind(_driver.ChatDriver, singleton=True),
|
|
55
|
+
|
|
56
|
+
inj.bind_late(_driver.ChatDriver),
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
#
|
|
60
|
+
|
|
61
|
+
els.append(inj.bind(DefaultBackendName, to_const=DEFAULT_BACKEND))
|
|
62
|
+
|
|
63
|
+
#
|
|
64
|
+
|
|
65
|
+
els.append(inj.bind(_types.ChatDriverId(uuid.uuid4())))
|
|
66
|
+
|
|
67
|
+
#
|
|
68
|
+
|
|
69
|
+
return inj.as_elements(*els)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from omlish import inject as inj
|
|
2
2
|
from omlish import lang
|
|
3
3
|
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from
|
|
4
|
+
from ..phases.injection import phase_callbacks
|
|
5
|
+
from ..phases.types import ChatPhase
|
|
6
|
+
from ..phases.types import ChatPhaseCallback
|
|
7
7
|
from .configs import StateConfig
|
|
8
8
|
|
|
9
9
|
|