ommlds 0.0.0.dev490__py3-none-any.whl → 0.0.0.dev492__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 (88) hide show
  1. ommlds/.omlish-manifests.json +9 -7
  2. ommlds/README.md +11 -0
  3. ommlds/__about__.py +1 -1
  4. ommlds/backends/ollama/_dataclasses.py +53 -23
  5. ommlds/backends/ollama/protocol.py +3 -0
  6. ommlds/cli/_dataclasses.py +439 -289
  7. ommlds/cli/main.py +42 -34
  8. ommlds/cli/rendering/types.py +6 -0
  9. ommlds/cli/sessions/chat/configs.py +2 -2
  10. ommlds/cli/sessions/chat/{agents → drivers}/ai/inject.py +3 -1
  11. ommlds/cli/sessions/chat/{agents → drivers}/configs.py +1 -1
  12. ommlds/cli/sessions/chat/{agents/agent.py → drivers/driver.py} +7 -1
  13. ommlds/cli/sessions/chat/{agents → drivers}/inject.py +13 -6
  14. ommlds/cli/sessions/chat/{agents → drivers}/tools/configs.py +0 -2
  15. ommlds/cli/sessions/chat/drivers/tools/confirmation.py +44 -0
  16. ommlds/cli/sessions/chat/{agents → drivers}/tools/execution.py +2 -3
  17. ommlds/cli/sessions/chat/{agents → drivers}/tools/inject.py +1 -13
  18. ommlds/cli/sessions/chat/{agents → drivers}/tools/rendering.py +1 -1
  19. ommlds/cli/sessions/chat/drivers/types.py +10 -0
  20. ommlds/cli/sessions/chat/{agents → drivers}/user/inject.py +5 -5
  21. ommlds/cli/sessions/chat/inject.py +2 -2
  22. ommlds/cli/sessions/chat/interfaces/bare/inject.py +23 -0
  23. ommlds/cli/sessions/chat/interfaces/bare/interactive.py +12 -6
  24. ommlds/cli/sessions/chat/interfaces/bare/oneshot.py +5 -5
  25. ommlds/cli/sessions/chat/{agents/tools/confirmation.py → interfaces/bare/tools.py} +2 -21
  26. ommlds/cli/sessions/chat/interfaces/bare/user.py +1 -1
  27. ommlds/cli/sessions/chat/interfaces/configs.py +8 -0
  28. ommlds/cli/sessions/chat/interfaces/inject.py +1 -1
  29. ommlds/cli/sessions/chat/interfaces/textual/app.py +154 -103
  30. ommlds/cli/sessions/chat/interfaces/textual/inject.py +34 -9
  31. ommlds/cli/sessions/chat/interfaces/textual/interface.py +85 -0
  32. ommlds/cli/sessions/chat/interfaces/textual/styles/__init__.py +29 -0
  33. ommlds/cli/sessions/chat/interfaces/textual/styles/input.tcss +3 -1
  34. ommlds/cli/sessions/chat/interfaces/textual/styles/markdown.tcss +7 -0
  35. ommlds/cli/sessions/chat/interfaces/textual/styles/messages.tcss +131 -9
  36. ommlds/cli/sessions/chat/interfaces/textual/tools.py +37 -0
  37. ommlds/cli/sessions/chat/interfaces/textual/widgets/__init__.py +0 -0
  38. ommlds/cli/sessions/chat/interfaces/textual/widgets/input.py +36 -0
  39. ommlds/cli/sessions/chat/interfaces/textual/widgets/messages.py +164 -0
  40. ommlds/minichain/backends/impls/ollama/chat.py +50 -56
  41. ommlds/minichain/backends/impls/ollama/protocol.py +144 -0
  42. ommlds/minichain/backends/impls/openai/names.py +3 -1
  43. ommlds/nanochat/rustbpe/README.md +9 -0
  44. {ommlds-0.0.0.dev490.dist-info → ommlds-0.0.0.dev492.dist-info}/METADATA +6 -6
  45. {ommlds-0.0.0.dev490.dist-info → ommlds-0.0.0.dev492.dist-info}/RECORD +88 -78
  46. /ommlds/cli/sessions/chat/{agents → drivers}/__init__.py +0 -0
  47. /ommlds/cli/sessions/chat/{agents → drivers}/ai/__init__.py +0 -0
  48. /ommlds/cli/sessions/chat/{agents → drivers}/ai/configs.py +0 -0
  49. /ommlds/cli/sessions/chat/{agents → drivers}/ai/events.py +0 -0
  50. /ommlds/cli/sessions/chat/{agents → drivers}/ai/injection.py +0 -0
  51. /ommlds/cli/sessions/chat/{agents → drivers}/ai/rendering.py +0 -0
  52. /ommlds/cli/sessions/chat/{agents → drivers}/ai/services.py +0 -0
  53. /ommlds/cli/sessions/chat/{agents → drivers}/ai/tools.py +0 -0
  54. /ommlds/cli/sessions/chat/{agents → drivers}/ai/types.py +0 -0
  55. /ommlds/cli/sessions/chat/{agents → drivers}/events/__init__.py +0 -0
  56. /ommlds/cli/sessions/chat/{agents → drivers}/events/inject.py +0 -0
  57. /ommlds/cli/sessions/chat/{agents → drivers}/events/injection.py +0 -0
  58. /ommlds/cli/sessions/chat/{agents → drivers}/events/manager.py +0 -0
  59. /ommlds/cli/sessions/chat/{agents → drivers}/events/types.py +0 -0
  60. /ommlds/cli/sessions/chat/{agents → drivers}/phases/__init__.py +0 -0
  61. /ommlds/cli/sessions/chat/{agents → drivers}/phases/inject.py +0 -0
  62. /ommlds/cli/sessions/chat/{agents → drivers}/phases/injection.py +0 -0
  63. /ommlds/cli/sessions/chat/{agents → drivers}/phases/manager.py +0 -0
  64. /ommlds/cli/sessions/chat/{agents → drivers}/phases/types.py +0 -0
  65. /ommlds/cli/sessions/chat/{agents → drivers}/state/__init__.py +0 -0
  66. /ommlds/cli/sessions/chat/{agents → drivers}/state/configs.py +0 -0
  67. /ommlds/cli/sessions/chat/{agents → drivers}/state/inject.py +0 -0
  68. /ommlds/cli/sessions/chat/{agents → drivers}/state/inmemory.py +0 -0
  69. /ommlds/cli/sessions/chat/{agents → drivers}/state/storage.py +0 -0
  70. /ommlds/cli/sessions/chat/{agents → drivers}/state/types.py +0 -0
  71. /ommlds/cli/sessions/chat/{agents → drivers}/tools/__init__.py +0 -0
  72. /ommlds/cli/sessions/chat/{agents → drivers}/tools/fs/__init__.py +0 -0
  73. /ommlds/cli/sessions/chat/{agents → drivers}/tools/fs/configs.py +0 -0
  74. /ommlds/cli/sessions/chat/{agents → drivers}/tools/fs/inject.py +0 -0
  75. /ommlds/cli/sessions/chat/{agents → drivers}/tools/injection.py +0 -0
  76. /ommlds/cli/sessions/chat/{agents → drivers}/tools/todo/__init__.py +0 -0
  77. /ommlds/cli/sessions/chat/{agents → drivers}/tools/todo/configs.py +0 -0
  78. /ommlds/cli/sessions/chat/{agents → drivers}/tools/todo/inject.py +0 -0
  79. /ommlds/cli/sessions/chat/{agents → drivers}/tools/weather/__init__.py +0 -0
  80. /ommlds/cli/sessions/chat/{agents → drivers}/tools/weather/configs.py +0 -0
  81. /ommlds/cli/sessions/chat/{agents → drivers}/tools/weather/inject.py +0 -0
  82. /ommlds/cli/sessions/chat/{agents → drivers}/tools/weather/tools.py +0 -0
  83. /ommlds/cli/sessions/chat/{agents → drivers}/user/__init__.py +0 -0
  84. /ommlds/cli/sessions/chat/{agents → drivers}/user/configs.py +0 -0
  85. {ommlds-0.0.0.dev490.dist-info → ommlds-0.0.0.dev492.dist-info}/WHEEL +0 -0
  86. {ommlds-0.0.0.dev490.dist-info → ommlds-0.0.0.dev492.dist-info}/entry_points.txt +0 -0
  87. {ommlds-0.0.0.dev490.dist-info → ommlds-0.0.0.dev492.dist-info}/licenses/LICENSE +0 -0
  88. {ommlds-0.0.0.dev490.dist-info → ommlds-0.0.0.dev492.dist-info}/top_level.txt +0 -0
ommlds/cli/main.py CHANGED
@@ -36,7 +36,8 @@ def _process_main_extra_args(args: ap.Namespace) -> None:
36
36
  logs.configure_standard_logging('DEBUG')
37
37
  else:
38
38
  logs.configure_standard_logging('INFO')
39
- logs.silence_noisy_loggers()
39
+
40
+ logs.silence_noisy_loggers()
40
41
 
41
42
 
42
43
  ##
@@ -69,10 +70,10 @@ class ChatProfile(Profile):
69
70
  def configure_backend(self, cfg: ChatConfig) -> ChatConfig:
70
71
  return dc.replace(
71
72
  cfg,
72
- agent=dc.replace(
73
- cfg.agent,
73
+ driver=dc.replace(
74
+ cfg.driver,
74
75
  backend=dc.replace(
75
- cfg.agent.backend,
76
+ cfg.driver.backend,
76
77
  backend=self._args.backend,
77
78
  ),
78
79
  ),
@@ -104,10 +105,10 @@ class ChatProfile(Profile):
104
105
  else:
105
106
  cfg = dc.replace(
106
107
  cfg,
107
- agent=dc.replace(
108
- cfg.agent,
108
+ driver=dc.replace(
109
+ cfg.driver,
109
110
  ai=dc.replace(
110
- cfg.agent.ai,
111
+ cfg.driver.ai,
111
112
  verbose=True,
112
113
  ),
113
114
  ),
@@ -133,10 +134,10 @@ class ChatProfile(Profile):
133
134
  # TODO: '-' -> stdin
134
135
  cfg = dc.replace(
135
136
  cfg,
136
- agent=dc.replace(
137
- cfg.agent,
137
+ driver=dc.replace(
138
+ cfg.driver,
138
139
  user=dc.replace(
139
- cfg.agent.user,
140
+ cfg.driver.user,
140
141
  initial_user_content=' '.join(self._args.message),
141
142
  ),
142
143
  ),
@@ -157,10 +158,10 @@ class ChatProfile(Profile):
157
158
  def configure_state(self, cfg: ChatConfig) -> ChatConfig:
158
159
  return dc.replace(
159
160
  cfg,
160
- agent=dc.replace(
161
- cfg.agent,
161
+ driver=dc.replace(
162
+ cfg.driver,
162
163
  state=dc.replace(
163
- cfg.agent.state,
164
+ cfg.driver.state,
164
165
  state='ephemeral' if self._args.ephemeral else 'new' if self._args.new else 'continue',
165
166
  ),
166
167
  ),
@@ -176,10 +177,10 @@ class ChatProfile(Profile):
176
177
  def configure_output(self, cfg: ChatConfig) -> ChatConfig:
177
178
  return dc.replace(
178
179
  cfg,
179
- agent=dc.replace(
180
- cfg.agent,
180
+ driver=dc.replace(
181
+ cfg.driver,
181
182
  ai=dc.replace(
182
- cfg.agent.ai,
183
+ cfg.driver.ai,
183
184
  stream=bool(self._args.stream),
184
185
  ),
185
186
  ),
@@ -199,30 +200,37 @@ class ChatProfile(Profile):
199
200
  ]
200
201
 
201
202
  def configure_tools(self, cfg: ChatConfig) -> ChatConfig:
203
+ if not (
204
+ self._args.enable_fs_tools or
205
+ self._args.enable_todo_tools or
206
+ # self._args.enable_unsafe_tools_do_not_use_lol or
207
+ self._args.enable_test_weather_tool or
208
+ self._args.code
209
+ ):
210
+ return cfg
211
+
202
212
  return dc.replace(
203
213
  cfg,
204
- agent=dc.replace(
205
- cfg.agent,
214
+ driver=dc.replace(
215
+ cfg.driver,
206
216
  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
- ),
217
+ cfg.driver.ai,
218
+ enable_tools=True,
215
219
  ),
216
220
  tools=dc.replace(
217
- cfg.agent.tools,
221
+ cfg.driver.tools,
218
222
  enabled_tools={ # noqa
219
- *(cfg.agent.tools.enabled_tools or []),
223
+ *(cfg.driver.tools.enabled_tools or []),
220
224
  *(['fs'] if self._args.enable_fs_tools else []),
221
225
  *(['todo'] if self._args.enable_todo_tools else []),
222
226
  *(['weather'] if self._args.enable_test_weather_tool else []),
223
227
  },
224
228
  ),
225
229
  ),
230
+ interface=dc.replace(
231
+ cfg.interface,
232
+ enable_tools=True,
233
+ ),
226
234
  )
227
235
 
228
236
  #
@@ -237,10 +245,10 @@ class ChatProfile(Profile):
237
245
 
238
246
  cfg = dc.replace(
239
247
  cfg,
240
- agent=dc.replace(
241
- cfg.agent,
248
+ driver=dc.replace(
249
+ cfg.driver,
242
250
  ai=dc.replace(
243
- cfg.agent.ai,
251
+ cfg.driver.ai,
244
252
  enable_tools=True,
245
253
  ),
246
254
  ),
@@ -252,10 +260,10 @@ class ChatProfile(Profile):
252
260
 
253
261
  cfg = dc.replace(
254
262
  cfg,
255
- agent=dc.replace(
256
- cfg.agent,
263
+ driver=dc.replace(
264
+ cfg.driver,
257
265
  user=dc.replace(
258
- cfg.agent.user,
266
+ cfg.driver.user,
259
267
  initial_system_content=system_content,
260
268
  ),
261
269
  ),
@@ -1,3 +1,9 @@
1
+ """
2
+ TODO:
3
+ - html?
4
+ - terminal?
5
+ - rich? textual.Content?
6
+ """
1
7
  import abc
2
8
  import typing as ta
3
9
 
@@ -1,7 +1,7 @@
1
1
  from omlish import dataclasses as dc
2
2
 
3
3
  from ...rendering.configs import RenderingConfig
4
- from .agents.configs import AgentConfig
4
+ from .drivers.configs import DriverConfig
5
5
  from .interfaces.configs import InterfaceConfig
6
6
 
7
7
 
@@ -16,6 +16,6 @@ DEFAULT_BACKEND = 'openai'
16
16
 
17
17
  @dc.dataclass(frozen=True, kw_only=True)
18
18
  class ChatConfig:
19
- agent: AgentConfig = AgentConfig()
19
+ driver: DriverConfig = DriverConfig()
20
20
  interface: InterfaceConfig = InterfaceConfig()
21
21
  rendering: RenderingConfig = RenderingConfig()
@@ -66,7 +66,9 @@ def bind_ai(cfg: AiConfig = AiConfig()) -> inj.Elements:
66
66
  #
67
67
 
68
68
  if cfg.enable_tools:
69
- def _provide_tools_chat_choices_options_provider(tc: mc.ToolCatalog) -> _services.ChatChoicesServiceOptionsProvider: # noqa
69
+ def _provide_tools_chat_choices_options_provider(
70
+ tc: mc.ToolCatalog,
71
+ ) -> _services.ChatChoicesServiceOptionsProvider:
70
72
  return _services.ChatChoicesServiceOptionsProvider(lambda: [
71
73
  mc.Tool(tce.spec)
72
74
  for tce in tc.by_name.values()
@@ -17,7 +17,7 @@ DEFAULT_BACKEND = 'openai'
17
17
 
18
18
 
19
19
  @dc.dataclass(frozen=True, kw_only=True)
20
- class AgentConfig:
20
+ class DriverConfig:
21
21
  ai: AiConfig = AiConfig()
22
22
  backend: BackendConfig = BackendConfig()
23
23
  state: StateConfig = StateConfig()
@@ -3,6 +3,8 @@ TODO:
3
3
  - lifecycles
4
4
  - StreamService
5
5
  """
6
+ from omlish import lang
7
+
6
8
  from ..... import minichain as mc
7
9
  from .ai.types import AiChatGenerator
8
10
  from .events.manager import ChatEventsManager
@@ -15,7 +17,11 @@ from .state.types import ChatStateManager
15
17
  ##
16
18
 
17
19
 
18
- class ChatAgent:
20
+ class ChatDriverGetter(lang.Func0['ChatDriver']):
21
+ pass
22
+
23
+
24
+ class ChatDriver:
19
25
  def __init__(
20
26
  self,
21
27
  *,
@@ -1,18 +1,21 @@
1
1
  """
2
2
  TODO:
3
- - private + expose(ChatAgent)
3
+ - private + expose(ChatDriver)
4
4
  """
5
+ import uuid
6
+
5
7
  from omlish import inject as inj
6
8
  from omlish import lang
7
9
 
8
10
  from ....backends.types import DefaultBackendName
9
11
  from .configs import DEFAULT_BACKEND
10
- from .configs import AgentConfig
12
+ from .configs import DriverConfig
11
13
 
12
14
 
13
15
  with lang.auto_proxy_import(globals()):
14
16
  from ....backends import inject as _backends
15
- from . import agent as _agent
17
+ from . import driver as _driver
18
+ from . import types as _types
16
19
  from .ai import inject as _ai
17
20
  from .events import inject as _events
18
21
  from .phases import inject as _phases
@@ -24,7 +27,7 @@ with lang.auto_proxy_import(globals()):
24
27
  ##
25
28
 
26
29
 
27
- def bind_agent(cfg: AgentConfig) -> inj.Elements:
30
+ def bind_driver(cfg: DriverConfig) -> inj.Elements:
28
31
  els: list[inj.Elemental] = []
29
32
 
30
33
  #
@@ -48,9 +51,9 @@ def bind_agent(cfg: AgentConfig) -> inj.Elements:
48
51
  #
49
52
 
50
53
  els.extend([
51
- inj.bind(_agent.ChatAgent, singleton=True),
54
+ inj.bind(_driver.ChatDriver, singleton=True),
52
55
 
53
- inj.bind_late(_agent.ChatAgent),
56
+ inj.bind_late(_driver.ChatDriver, _driver.ChatDriverGetter),
54
57
  ])
55
58
 
56
59
  #
@@ -59,4 +62,8 @@ def bind_agent(cfg: AgentConfig) -> inj.Elements:
59
62
 
60
63
  #
61
64
 
65
+ els.append(inj.bind(_types.ChatDriverId(uuid.uuid4())))
66
+
67
+ #
68
+
62
69
  return inj.as_elements(*els)
@@ -9,8 +9,6 @@ from omlish import lang
9
9
 
10
10
  @dc.dataclass(frozen=True, kw_only=True)
11
11
  class ToolsConfig:
12
- dangerous_no_confirmation: bool = False
13
-
14
12
  enabled_tools: ta.Iterable[str] | None = None
15
13
 
16
14
  verbose: bool = False
@@ -0,0 +1,44 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+ from omlish import lang
5
+
6
+ from ...... import minichain as mc
7
+
8
+
9
+ ##
10
+
11
+
12
+ class ToolExecutionRequestDeniedError(Exception):
13
+ pass
14
+
15
+
16
+ class ToolExecutionConfirmation(lang.Abstract):
17
+ @abc.abstractmethod
18
+ def confirm_tool_execution_or_raise(
19
+ self,
20
+ use: 'mc.ToolUse',
21
+ entry: 'mc.ToolCatalogEntry',
22
+ ) -> ta.Awaitable[None]:
23
+ raise NotImplementedError
24
+
25
+
26
+ ##
27
+
28
+
29
+ class AlwaysDenyToolExecutionConfirmation(ToolExecutionConfirmation):
30
+ async def confirm_tool_execution_or_raise(
31
+ self,
32
+ use: 'mc.ToolUse',
33
+ entry: 'mc.ToolCatalogEntry',
34
+ ) -> None:
35
+ raise ToolExecutionRequestDeniedError
36
+
37
+
38
+ class UnsafeAlwaysAllowToolExecutionConfirmation(ToolExecutionConfirmation):
39
+ async def confirm_tool_execution_or_raise(
40
+ self,
41
+ use: 'mc.ToolUse',
42
+ entry: 'mc.ToolCatalogEntry',
43
+ ) -> None:
44
+ pass
@@ -37,7 +37,7 @@ class ToolUseExecutorImpl(ToolUseExecutor):
37
37
  *,
38
38
  catalog: 'mc.ToolCatalog',
39
39
  ctx_provider: ToolContextProvider,
40
- confirmation: ToolExecutionConfirmation | None = None,
40
+ confirmation: ToolExecutionConfirmation,
41
41
  ) -> None:
42
42
  super().__init__()
43
43
 
@@ -52,8 +52,7 @@ class ToolUseExecutorImpl(ToolUseExecutor):
52
52
  ) -> 'mc.ToolUseResultMessage':
53
53
  tce = self._catalog.by_name[check.non_empty_str(use.name)]
54
54
 
55
- if self._confirmation is not None:
56
- await self._confirmation.confirm_tool_execution_or_raise(use, tce)
55
+ await self._confirmation.confirm_tool_execution_or_raise(use, tce)
57
56
 
58
57
  return await mc.execute_tool_use(
59
58
  mc.ToolContext(
@@ -10,7 +10,6 @@ from .injection import tool_context_providers
10
10
 
11
11
 
12
12
  with lang.auto_proxy_import(globals()):
13
- from . import confirmation as _confirmation
14
13
  from . import execution as _execution
15
14
  from . import rendering as _rendering
16
15
 
@@ -59,26 +58,15 @@ def bind_tools(cfg: ToolsConfig = ToolsConfig()) -> inj.Elements:
59
58
  els.append(exec_stack.push_bind(to_ctor=_execution.ToolUseExecutorImpl, singleton=True))
60
59
 
61
60
  if cfg.verbose:
61
+ els.append(exec_stack.push_bind(to_ctor=_rendering.ArgsRenderingToolUseExecutor, singleton=True))
62
62
  els.append(exec_stack.push_bind(to_ctor=_rendering.ResultRenderingToolUseExecutor, singleton=True))
63
63
 
64
- if cfg.dangerous_no_confirmation:
65
- els.append(exec_stack.push_bind(to_ctor=_rendering.ArgsRenderingToolUseExecutor, singleton=True))
66
-
67
64
  els.extend([
68
65
  inj.bind(_execution.ToolUseExecutor, to_key=exec_stack.top),
69
66
  ])
70
67
 
71
68
  #
72
69
 
73
- if not cfg.dangerous_no_confirmation:
74
- els.append(inj.bind(
75
- _confirmation.ToolExecutionConfirmation,
76
- to_ctor=_confirmation.InteractiveToolExecutionConfirmation,
77
- singleton=True,
78
- ))
79
-
80
- #
81
-
82
70
  els.extend([
83
71
  tool_context_providers().bind_items_provider(singleton=True),
84
72
 
@@ -2,7 +2,7 @@ import typing as ta
2
2
 
3
3
  from ...... import minichain as mc
4
4
  from .....rendering.types import ContentRendering
5
- from ...agents.tools.execution import ToolUseExecutor
5
+ from ...drivers.tools.execution import ToolUseExecutor
6
6
 
7
7
 
8
8
  ##
@@ -0,0 +1,10 @@
1
+ import uuid
2
+
3
+ from omlish import typedvalues as tv
4
+
5
+
6
+ ##
7
+
8
+
9
+ class ChatDriverId(tv.UniqueScalarTypedValue[uuid.UUID]):
10
+ pass
@@ -9,7 +9,7 @@ from .configs import UserConfig
9
9
 
10
10
 
11
11
  with lang.auto_proxy_import(globals()):
12
- from .. import agent as _agent
12
+ from .. import driver as _driver
13
13
  from ..state import types as _state
14
14
 
15
15
 
@@ -29,12 +29,12 @@ def bind_user(cfg: UserConfig = UserConfig()) -> inj.Elements:
29
29
  )))
30
30
 
31
31
  if cfg.initial_user_content is not None:
32
- async def add_initial_user_content(ca: '_agent.ChatAgent') -> None:
33
- await ca.send_user_messages([mc.UserMessage(cfg.initial_user_content)])
32
+ async def add_initial_user_content(cd: '_driver.ChatDriver') -> None:
33
+ await cd.send_user_messages([mc.UserMessage(cfg.initial_user_content)])
34
34
 
35
35
  els.append(phase_callbacks().bind_item(to_fn=inj.KwargsTarget.of(
36
- lambda ca: ChatPhaseCallback(ChatPhase.STARTED, lambda: add_initial_user_content(ca())),
37
- ca=inj.Late[_agent.ChatAgent],
36
+ lambda cdg: ChatPhaseCallback(ChatPhase.STARTED, lambda: add_initial_user_content(cdg())),
37
+ cdg=_driver.ChatDriverGetter,
38
38
  )))
39
39
 
40
40
  return inj.as_elements(*els)
@@ -9,7 +9,7 @@ from .configs import ChatConfig
9
9
  with lang.auto_proxy_import(globals()):
10
10
  from ...rendering import inject as _rendering
11
11
  from . import session as _session
12
- from .agents import inject as _agents
12
+ from .drivers import inject as _drivers
13
13
  from .interfaces import inject as _interfaces
14
14
 
15
15
 
@@ -22,7 +22,7 @@ def bind_chat(cfg: ChatConfig) -> inj.Elements:
22
22
  #
23
23
 
24
24
  els.extend([
25
- _agents.bind_agent(cfg.agent),
25
+ _drivers.bind_driver(cfg.driver),
26
26
 
27
27
  _interfaces.bind_interface(cfg.interface),
28
28
 
@@ -8,8 +8,10 @@ from ..configs import InterfaceConfig
8
8
  with lang.auto_proxy_import(globals()):
9
9
  from .....inputs import asyncs as _inputs_asyncs
10
10
  from .....inputs import sync as _inputs_sync
11
+ from ...drivers.tools import confirmation as _tools_confirmation
11
12
  from . import interactive as _interactive
12
13
  from . import oneshot as _oneshot
14
+ from . import tools as _tools
13
15
 
14
16
 
15
17
  ##
@@ -18,6 +20,8 @@ with lang.auto_proxy_import(globals()):
18
20
  def bind_bare(cfg: InterfaceConfig = InterfaceConfig()) -> inj.Elements:
19
21
  els: list[inj.Elemental] = []
20
22
 
23
+ #
24
+
21
25
  if cfg.interactive:
22
26
  els.extend([
23
27
  inj.bind(_interactive.InteractiveBareChatInterface, singleton=True),
@@ -35,4 +39,23 @@ def bind_bare(cfg: InterfaceConfig = InterfaceConfig()) -> inj.Elements:
35
39
  inj.bind(ChatInterface, to_key=_oneshot.OneshotBareChatInterface),
36
40
  ])
37
41
 
42
+ #
43
+
44
+ if cfg.enable_tools:
45
+ if cfg.dangerous_no_tool_confirmation:
46
+ els.append(inj.bind(
47
+ _tools_confirmation.ToolExecutionConfirmation,
48
+ to_ctor=_tools_confirmation.UnsafeAlwaysAllowToolExecutionConfirmation,
49
+ singleton=True,
50
+ ))
51
+
52
+ else:
53
+ els.append(inj.bind(
54
+ _tools_confirmation.ToolExecutionConfirmation,
55
+ to_ctor=_tools.InteractiveToolExecutionConfirmation,
56
+ singleton=True,
57
+ ))
58
+
59
+ #
60
+
38
61
  return inj.as_elements(*els)
@@ -4,7 +4,7 @@ from ...... import minichain as mc
4
4
  from .....inputs.asyncs import AsyncStringInput
5
5
  from .....inputs.asyncs import SyncAsyncStringInput
6
6
  from .....inputs.sync import InputSyncStringInput
7
- from ...agents.agent import ChatAgent
7
+ from ...drivers.driver import ChatDriver
8
8
  from ..base import ChatInterface
9
9
 
10
10
 
@@ -17,18 +17,18 @@ class InteractiveBareChatInterface(ChatInterface):
17
17
  def __init__(
18
18
  self,
19
19
  *,
20
- agent: ChatAgent,
20
+ driver: ChatDriver,
21
21
  string_input: AsyncStringInput | None = None,
22
22
  ) -> None:
23
23
  super().__init__()
24
24
 
25
- self._agent = agent
25
+ self._driver = driver
26
26
  if string_input is None:
27
27
  string_input = self.DEFAULT_STRING_INPUT
28
28
  self._string_input = string_input
29
29
 
30
30
  async def run(self) -> None:
31
- await self._agent.start()
31
+ await self._driver.start()
32
32
 
33
33
  while True:
34
34
  try:
@@ -36,6 +36,12 @@ class InteractiveBareChatInterface(ChatInterface):
36
36
  except EOFError:
37
37
  break
38
38
 
39
- await self._agent.send_user_messages([mc.UserMessage(s)])
39
+ print()
40
+ print('<')
41
+ print()
40
42
 
41
- await self._agent.stop()
43
+ await self._driver.send_user_messages([mc.UserMessage(s)])
44
+
45
+ print()
46
+
47
+ await self._driver.stop()
@@ -1,4 +1,4 @@
1
- from ...agents.agent import ChatAgent
1
+ from ...drivers.driver import ChatDriver
2
2
  from ..base import ChatInterface
3
3
 
4
4
 
@@ -9,13 +9,13 @@ class OneshotBareChatInterface(ChatInterface):
9
9
  def __init__(
10
10
  self,
11
11
  *,
12
- agent: ChatAgent,
12
+ driver: ChatDriver,
13
13
  ) -> None:
14
14
  super().__init__()
15
15
 
16
- self._agent = agent
16
+ self._driver = driver
17
17
 
18
18
  async def run(self) -> None:
19
- await self._agent.start()
19
+ await self._driver.start()
20
20
 
21
- await self._agent.stop()
21
+ await self._driver.stop()
@@ -1,28 +1,9 @@
1
- import abc
2
- import typing as ta
3
-
4
- from omlish import lang
5
1
  from omlish.formats import json
6
2
  from omlish.term.confirm import confirm_action
7
3
 
8
4
  from ...... import minichain as mc
9
-
10
-
11
- ##
12
-
13
-
14
- class ToolExecutionRequestDeniedError(Exception):
15
- pass
16
-
17
-
18
- class ToolExecutionConfirmation(lang.Abstract):
19
- @abc.abstractmethod
20
- def confirm_tool_execution_or_raise(
21
- self,
22
- use: 'mc.ToolUse',
23
- entry: 'mc.ToolCatalogEntry',
24
- ) -> ta.Awaitable[None]:
25
- raise NotImplementedError
5
+ from ...drivers.tools.confirmation import ToolExecutionConfirmation
6
+ from ...drivers.tools.confirmation import ToolExecutionRequestDeniedError
26
7
 
27
8
 
28
9
  ##
@@ -4,7 +4,7 @@ from ...... import minichain as mc
4
4
  from .....inputs.asyncs import AsyncStringInput
5
5
  from .....inputs.asyncs import SyncAsyncStringInput
6
6
  from .....inputs.sync import InputSyncStringInput
7
- from ...agents.user.types import UserChatInput
7
+ from ...drivers.user.types import UserChatInput
8
8
 
9
9
 
10
10
  ##
@@ -1,3 +1,8 @@
1
+ """
2
+ TODO:
3
+ - obviously, subclasses of InterfaceConfig
4
+ - this is really just another instance of the whole `argparse -> config -> inject` flow
5
+ """
1
6
  import typing as ta
2
7
 
3
8
  from omlish import dataclasses as dc
@@ -13,3 +18,6 @@ class InterfaceConfig:
13
18
  use_textual: bool = False
14
19
 
15
20
  use_readline: bool | ta.Literal['auto'] = 'auto'
21
+
22
+ enable_tools: bool = False
23
+ dangerous_no_tool_confirmation: bool = False
@@ -16,7 +16,7 @@ def bind_interface(cfg: InterfaceConfig = InterfaceConfig()) -> inj.Elements:
16
16
  els: list[inj.Elemental] = []
17
17
 
18
18
  if cfg.use_textual:
19
- els.append(_textual.bind_textual())
19
+ els.append(_textual.bind_textual(cfg))
20
20
 
21
21
  else:
22
22
  els.append(_bare.bind_bare(cfg))