ommlds 0.0.0.dev489__py3-none-any.whl → 0.0.0.dev490__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. ommlds/cli/_dataclasses.py +657 -328
  2. ommlds/cli/main.py +74 -42
  3. ommlds/cli/sessions/chat/agents/agent.py +49 -0
  4. ommlds/cli/sessions/chat/{chat → agents}/ai/configs.py +3 -1
  5. ommlds/cli/sessions/chat/agents/ai/events.py +57 -0
  6. ommlds/cli/sessions/chat/{chat → agents}/ai/inject.py +7 -2
  7. ommlds/cli/sessions/chat/{chat → agents}/ai/rendering.py +1 -1
  8. ommlds/cli/sessions/chat/{chat → agents}/ai/services.py +1 -1
  9. ommlds/cli/sessions/chat/{chat → agents}/ai/tools.py +1 -1
  10. ommlds/cli/sessions/chat/{chat → agents}/ai/types.py +9 -0
  11. ommlds/cli/sessions/chat/agents/configs.py +25 -0
  12. ommlds/cli/sessions/chat/agents/events/inject.py +27 -0
  13. ommlds/cli/sessions/chat/agents/events/injection.py +14 -0
  14. ommlds/cli/sessions/chat/agents/events/manager.py +16 -0
  15. ommlds/cli/sessions/chat/agents/events/types.py +38 -0
  16. ommlds/cli/sessions/chat/agents/inject.py +62 -0
  17. ommlds/cli/sessions/chat/{chat → agents}/state/inject.py +3 -3
  18. ommlds/cli/sessions/chat/{chat → agents}/state/types.py +1 -1
  19. ommlds/cli/sessions/chat/{tools → agents/tools}/configs.py +3 -1
  20. ommlds/cli/sessions/chat/{tools → agents/tools}/confirmation.py +1 -1
  21. ommlds/cli/sessions/chat/{tools → agents/tools}/execution.py +1 -1
  22. ommlds/cli/sessions/chat/{tools → agents/tools}/fs/inject.py +3 -3
  23. ommlds/cli/sessions/chat/{tools → agents/tools}/inject.py +8 -4
  24. ommlds/cli/sessions/chat/{tools → agents/tools}/injection.py +1 -1
  25. ommlds/cli/sessions/chat/{tools → agents/tools}/rendering.py +3 -3
  26. ommlds/cli/sessions/chat/{tools → agents/tools}/todo/inject.py +3 -3
  27. ommlds/cli/sessions/chat/{tools → agents/tools}/weather/tools.py +1 -1
  28. ommlds/cli/sessions/chat/{chat → agents}/user/configs.py +0 -2
  29. ommlds/cli/sessions/chat/agents/user/inject.py +40 -0
  30. ommlds/cli/sessions/chat/configs.py +4 -12
  31. ommlds/cli/sessions/chat/inject.py +4 -32
  32. ommlds/cli/sessions/chat/{interface → interfaces}/bare/inject.py +13 -7
  33. ommlds/cli/sessions/chat/interfaces/bare/interactive.py +41 -0
  34. ommlds/cli/sessions/chat/interfaces/bare/oneshot.py +21 -0
  35. ommlds/cli/sessions/chat/{interface → interfaces}/bare/user.py +1 -1
  36. ommlds/cli/sessions/chat/interfaces/textual/__init__.py +0 -0
  37. ommlds/cli/sessions/chat/interfaces/textual/app.py +211 -0
  38. ommlds/cli/sessions/chat/interfaces/textual/inject.py +43 -0
  39. ommlds/cli/sessions/chat/{interface → interfaces}/textual/interface.py +0 -3
  40. ommlds/cli/sessions/chat/interfaces/textual/styles/__init__.py +0 -0
  41. ommlds/cli/sessions/chat/interfaces/textual/styles/input.tcss +51 -0
  42. ommlds/cli/sessions/chat/interfaces/textual/styles/messages.tcss +33 -0
  43. ommlds/cli/sessions/chat/session.py +1 -1
  44. {ommlds-0.0.0.dev489.dist-info → ommlds-0.0.0.dev490.dist-info}/METADATA +4 -4
  45. {ommlds-0.0.0.dev489.dist-info → ommlds-0.0.0.dev490.dist-info}/RECORD +76 -67
  46. ommlds/cli/sessions/chat/chat/user/inject.py +0 -52
  47. ommlds/cli/sessions/chat/chat/user/oneshot.py +0 -25
  48. ommlds/cli/sessions/chat/chat/user/types.py +0 -15
  49. ommlds/cli/sessions/chat/driver.py +0 -43
  50. ommlds/cli/sessions/chat/interface/bare/interface.py +0 -19
  51. ommlds/cli/sessions/chat/interface/textual/app.py +0 -191
  52. ommlds/cli/sessions/chat/interface/textual/inject.py +0 -27
  53. ommlds/cli/sessions/chat/interface/textual/user.py +0 -20
  54. /ommlds/cli/sessions/chat/{chat → agents}/__init__.py +0 -0
  55. /ommlds/cli/sessions/chat/{chat → agents}/ai/__init__.py +0 -0
  56. /ommlds/cli/sessions/chat/{chat → agents}/ai/injection.py +0 -0
  57. /ommlds/cli/sessions/chat/{chat/state → agents/events}/__init__.py +0 -0
  58. /ommlds/cli/sessions/chat/{chat/user → agents/phases}/__init__.py +0 -0
  59. /ommlds/cli/sessions/chat/{phases → agents/phases}/inject.py +0 -0
  60. /ommlds/cli/sessions/chat/{phases → agents/phases}/injection.py +0 -0
  61. /ommlds/cli/sessions/chat/{phases → agents/phases}/manager.py +0 -0
  62. /ommlds/cli/sessions/chat/{phases → agents/phases}/types.py +0 -0
  63. /ommlds/cli/sessions/chat/{interface → agents/state}/__init__.py +0 -0
  64. /ommlds/cli/sessions/chat/{chat → agents}/state/configs.py +0 -0
  65. /ommlds/cli/sessions/chat/{chat → agents}/state/inmemory.py +0 -0
  66. /ommlds/cli/sessions/chat/{chat → agents}/state/storage.py +0 -0
  67. /ommlds/cli/sessions/chat/{interface/bare → agents/tools}/__init__.py +0 -0
  68. /ommlds/cli/sessions/chat/{interface/textual → agents/tools/fs}/__init__.py +0 -0
  69. /ommlds/cli/sessions/chat/{tools → agents/tools}/fs/configs.py +0 -0
  70. /ommlds/cli/sessions/chat/{phases → agents/tools/todo}/__init__.py +0 -0
  71. /ommlds/cli/sessions/chat/{tools → agents/tools}/todo/configs.py +0 -0
  72. /ommlds/cli/sessions/chat/{tools → agents/tools/weather}/__init__.py +0 -0
  73. /ommlds/cli/sessions/chat/{tools → agents/tools}/weather/configs.py +0 -0
  74. /ommlds/cli/sessions/chat/{tools → agents/tools}/weather/inject.py +0 -0
  75. /ommlds/cli/sessions/chat/{tools/fs → agents/user}/__init__.py +0 -0
  76. /ommlds/cli/sessions/chat/{tools/todo → interfaces}/__init__.py +0 -0
  77. /ommlds/cli/sessions/chat/{tools/weather → interfaces/bare}/__init__.py +0 -0
  78. /ommlds/cli/sessions/chat/{interface → interfaces}/base.py +0 -0
  79. /ommlds/cli/sessions/chat/{interface → interfaces}/configs.py +0 -0
  80. /ommlds/cli/sessions/chat/{interface → interfaces}/inject.py +0 -0
  81. {ommlds-0.0.0.dev489.dist-info → ommlds-0.0.0.dev490.dist-info}/WHEEL +0 -0
  82. {ommlds-0.0.0.dev489.dist-info → ommlds-0.0.0.dev490.dist-info}/entry_points.txt +0 -0
  83. {ommlds-0.0.0.dev489.dist-info → ommlds-0.0.0.dev490.dist-info}/licenses/LICENSE +0 -0
  84. {ommlds-0.0.0.dev489.dist-info → ommlds-0.0.0.dev490.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
- backend=dc.replace(
73
- cfg.backend,
74
- backend=self._args.backend,
72
+ agent=dc.replace(
73
+ cfg.agent,
74
+ backend=dc.replace(
75
+ cfg.agent.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.interactive:
95
+ if self._args.textual:
93
96
  cfg = dc.replace(
94
97
  cfg,
95
98
  interface=dc.replace(
96
99
  cfg.interface,
97
- interactive=True,
98
- use_textual=self._args.textual,
100
+ use_textual=True,
101
+ ),
102
+ )
103
+
104
+ else:
105
+ cfg = dc.replace(
106
+ cfg,
107
+ agent=dc.replace(
108
+ cfg.agent,
109
+ ai=dc.replace(
110
+ cfg.agent.ai,
111
+ verbose=True,
112
+ ),
99
113
  ),
100
- user=dc.replace(
101
- cfg.user,
102
- interactive=True,
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
- user=dc.replace(
123
- cfg.user,
124
- initial_user_content=' '.join(self._args.message),
136
+ agent=dc.replace(
137
+ cfg.agent,
138
+ user=dc.replace(
139
+ cfg.agent.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
- state=dc.replace(
144
- cfg.state,
145
- state='ephemeral' if self._args.ephemeral else 'new' if self._args.new else 'continue',
160
+ agent=dc.replace(
161
+ cfg.agent,
162
+ state=dc.replace(
163
+ cfg.agent.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
- ai=dc.replace(
160
- cfg.ai,
161
- stream=bool(self._args.stream),
179
+ agent=dc.replace(
180
+ cfg.agent,
181
+ ai=dc.replace(
182
+ cfg.agent.ai,
183
+ stream=bool(self._args.stream),
184
+ ),
162
185
  ),
163
186
  rendering=dc.replace(
164
187
  cfg.rendering,
@@ -178,24 +201,27 @@ class ChatProfile(Profile):
178
201
  def configure_tools(self, cfg: ChatConfig) -> ChatConfig:
179
202
  return dc.replace(
180
203
  cfg,
181
- ai=dc.replace(
182
- cfg.ai,
183
- enable_tools=(
184
- self._args.enable_fs_tools or
185
- self._args.enable_todo_tools or
186
- # self._args.enable_unsafe_tools_do_not_use_lol or
187
- self._args.enable_test_weather_tool or
188
- self._args.code
204
+ agent=dc.replace(
205
+ cfg.agent,
206
+ ai=dc.replace(
207
+ cfg.agent.ai,
208
+ enable_tools=(
209
+ self._args.enable_fs_tools or
210
+ self._args.enable_todo_tools or
211
+ # self._args.enable_unsafe_tools_do_not_use_lol or
212
+ self._args.enable_test_weather_tool or
213
+ self._args.code
214
+ ),
215
+ ),
216
+ tools=dc.replace(
217
+ cfg.agent.tools,
218
+ enabled_tools={ # noqa
219
+ *(cfg.agent.tools.enabled_tools or []),
220
+ *(['fs'] if self._args.enable_fs_tools else []),
221
+ *(['todo'] if self._args.enable_todo_tools else []),
222
+ *(['weather'] if self._args.enable_test_weather_tool else []),
223
+ },
189
224
  ),
190
- ),
191
- tools=dc.replace(
192
- cfg.tools,
193
- enabled_tools={ # noqa
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
- },
199
225
  ),
200
226
  )
201
227
 
@@ -211,9 +237,12 @@ class ChatProfile(Profile):
211
237
 
212
238
  cfg = dc.replace(
213
239
  cfg,
214
- ai=dc.replace(
215
- cfg.ai,
216
- enable_tools=True,
240
+ agent=dc.replace(
241
+ cfg.agent,
242
+ ai=dc.replace(
243
+ cfg.agent.ai,
244
+ enable_tools=True,
245
+ ),
217
246
  ),
218
247
  )
219
248
 
@@ -223,9 +252,12 @@ class ChatProfile(Profile):
223
252
 
224
253
  cfg = dc.replace(
225
254
  cfg,
226
- user=dc.replace(
227
- cfg.user,
228
- initial_system_content=system_content,
255
+ agent=dc.replace(
256
+ cfg.agent,
257
+ user=dc.replace(
258
+ cfg.agent.user,
259
+ initial_system_content=system_content,
260
+ ),
229
261
  ),
230
262
  )
231
263
 
@@ -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 ChatAgent:
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])
@@ -7,5 +7,7 @@ from omlish import dataclasses as dc
7
7
  @dc.dataclass(frozen=True, kw_only=True)
8
8
  class AiConfig:
9
9
  stream: bool = False
10
- silent: bool = False
10
+
11
+ verbose: bool = False
12
+
11
13
  enable_tools: bool = False
@@ -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 not cfg.silent:
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 not cfg.silent:
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
 
@@ -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:
@@ -1,5 +1,5 @@
1
1
  from ...... import minichain as mc
2
- from ...tools.execution import ToolUseExecutor
2
+ from ..tools.execution import ToolUseExecutor
3
3
  from .types import AiChatGenerator
4
4
 
5
5
 
@@ -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 AgentConfig:
21
+ ai: AiConfig = AiConfig()
22
+ backend: BackendConfig = BackendConfig()
23
+ state: StateConfig = StateConfig()
24
+ tools: ToolsConfig = ToolsConfig()
25
+ user: UserConfig = UserConfig()
@@ -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,62 @@
1
+ """
2
+ TODO:
3
+ - private + expose(ChatAgent)
4
+ """
5
+ from omlish import inject as inj
6
+ from omlish import lang
7
+
8
+ from ....backends.types import DefaultBackendName
9
+ from .configs import DEFAULT_BACKEND
10
+ from .configs import AgentConfig
11
+
12
+
13
+ with lang.auto_proxy_import(globals()):
14
+ from ....backends import inject as _backends
15
+ from . import agent as _agent
16
+ from .ai import inject as _ai
17
+ from .events import inject as _events
18
+ from .phases import inject as _phases
19
+ from .state import inject as _state
20
+ from .tools import inject as _tools
21
+ from .user import inject as _user
22
+
23
+
24
+ ##
25
+
26
+
27
+ def bind_agent(cfg: AgentConfig) -> inj.Elements:
28
+ els: list[inj.Elemental] = []
29
+
30
+ #
31
+
32
+ els.extend([
33
+ _backends.bind_backends(cfg.backend),
34
+
35
+ _ai.bind_ai(cfg.ai),
36
+
37
+ _events.bind_events(),
38
+
39
+ _phases.bind_phases(),
40
+
41
+ _state.bind_state(cfg.state),
42
+
43
+ _tools.bind_tools(cfg.tools),
44
+
45
+ _user.bind_user(cfg.user),
46
+ ])
47
+
48
+ #
49
+
50
+ els.extend([
51
+ inj.bind(_agent.ChatAgent, singleton=True),
52
+
53
+ inj.bind_late(_agent.ChatAgent),
54
+ ])
55
+
56
+ #
57
+
58
+ els.append(inj.bind(DefaultBackendName, to_const=DEFAULT_BACKEND))
59
+
60
+ #
61
+
62
+ 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 ...phases.injection import phase_callbacks
5
- from ...phases.types import ChatPhase
6
- from ...phases.types import ChatPhaseCallback
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
 
@@ -18,7 +18,7 @@ class ChatState:
18
18
  created_at: datetime.datetime = dc.field(default_factory=lang.utcnow)
19
19
  updated_at: datetime.datetime = dc.field(default_factory=lang.utcnow)
20
20
 
21
- chat: mc.Chat = ()
21
+ chat: 'mc.Chat' = ()
22
22
 
23
23
 
24
24
  ##
@@ -9,10 +9,12 @@ from omlish import lang
9
9
 
10
10
  @dc.dataclass(frozen=True, kw_only=True)
11
11
  class ToolsConfig:
12
- silent: bool = False
13
12
  dangerous_no_confirmation: bool = False
13
+
14
14
  enabled_tools: ta.Iterable[str] | None = None
15
15
 
16
+ verbose: bool = False
17
+
16
18
 
17
19
  ##
18
20
 
@@ -5,7 +5,7 @@ from omlish import lang
5
5
  from omlish.formats import json
6
6
  from omlish.term.confirm import confirm_action
7
7
 
8
- from ..... import minichain as mc
8
+ from ...... import minichain as mc
9
9
 
10
10
 
11
11
  ##
@@ -4,7 +4,7 @@ import typing as ta
4
4
  from omlish import check
5
5
  from omlish import lang
6
6
 
7
- from ..... import minichain as mc
7
+ from ...... import minichain as mc
8
8
  from .confirmation import ToolExecutionConfirmation
9
9
 
10
10
 
@@ -12,9 +12,9 @@ from .configs import FsToolSetConfig
12
12
 
13
13
 
14
14
  def bind_fs_tools(cfg: FsToolSetConfig) -> inj.Elements:
15
- from ......minichain.lib.fs.context import FsContext
16
- from ......minichain.lib.fs.tools.ls import ls_tool
17
- from ......minichain.lib.fs.tools.read import read_tool
15
+ from .......minichain.lib.fs.context import FsContext
16
+ from .......minichain.lib.fs.tools.ls import ls_tool
17
+ from .......minichain.lib.fs.tools.read import read_tool
18
18
 
19
19
  return inj.as_elements(
20
20
  tool_catalog_entries().bind_item_consts(
@@ -2,8 +2,8 @@ from omlish import check
2
2
  from omlish import inject as inj
3
3
  from omlish import lang
4
4
 
5
- from ..... import minichain as mc
6
- from .configs import ToolsConfig
5
+ from ...... import minichain as mc
6
+ from ..configs import ToolsConfig
7
7
  from .injection import ToolSetBinder
8
8
  from .injection import tool_catalog_entries
9
9
  from .injection import tool_context_providers
@@ -58,7 +58,7 @@ def bind_tools(cfg: ToolsConfig = ToolsConfig()) -> inj.Elements:
58
58
 
59
59
  els.append(exec_stack.push_bind(to_ctor=_execution.ToolUseExecutorImpl, singleton=True))
60
60
 
61
- if not cfg.silent:
61
+ if cfg.verbose:
62
62
  els.append(exec_stack.push_bind(to_ctor=_rendering.ResultRenderingToolUseExecutor, singleton=True))
63
63
 
64
64
  if cfg.dangerous_no_confirmation:
@@ -71,7 +71,11 @@ def bind_tools(cfg: ToolsConfig = ToolsConfig()) -> inj.Elements:
71
71
  #
72
72
 
73
73
  if not cfg.dangerous_no_confirmation:
74
- els.append(inj.bind(_confirmation.ToolExecutionConfirmation, to_ctor=_confirmation.InteractiveToolExecutionConfirmation, singleton=True)) # noqa
74
+ els.append(inj.bind(
75
+ _confirmation.ToolExecutionConfirmation,
76
+ to_ctor=_confirmation.InteractiveToolExecutionConfirmation,
77
+ singleton=True,
78
+ ))
75
79
 
76
80
  #
77
81
 
@@ -4,7 +4,7 @@ from omlish import dataclasses as dc
4
4
  from omlish import inject as inj
5
5
  from omlish import lang
6
6
 
7
- from ..... import minichain as mc
7
+ from ...... import minichain as mc
8
8
  from .configs import ToolSetConfig
9
9
 
10
10