ommlds 0.0.0.dev488__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 (83) 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 +14 -4
  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/{chat/user/interactive.py → 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.dev488.dist-info → ommlds-0.0.0.dev490.dist-info}/METADATA +4 -4
  45. {ommlds-0.0.0.dev488.dist-info → ommlds-0.0.0.dev490.dist-info}/RECORD +76 -66
  46. ommlds/cli/sessions/chat/chat/user/inject.py +0 -55
  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 -14
  52. ommlds/cli/sessions/chat/interface/textual/inject.py +0 -20
  53. /ommlds/cli/sessions/chat/{chat → agents}/__init__.py +0 -0
  54. /ommlds/cli/sessions/chat/{chat → agents}/ai/__init__.py +0 -0
  55. /ommlds/cli/sessions/chat/{chat → agents}/ai/injection.py +0 -0
  56. /ommlds/cli/sessions/chat/{chat/state → agents/events}/__init__.py +0 -0
  57. /ommlds/cli/sessions/chat/{chat/user → agents/phases}/__init__.py +0 -0
  58. /ommlds/cli/sessions/chat/{phases → agents/phases}/inject.py +0 -0
  59. /ommlds/cli/sessions/chat/{phases → agents/phases}/injection.py +0 -0
  60. /ommlds/cli/sessions/chat/{phases → agents/phases}/manager.py +0 -0
  61. /ommlds/cli/sessions/chat/{phases → agents/phases}/types.py +0 -0
  62. /ommlds/cli/sessions/chat/{interface → agents/state}/__init__.py +0 -0
  63. /ommlds/cli/sessions/chat/{chat → agents}/state/configs.py +0 -0
  64. /ommlds/cli/sessions/chat/{chat → agents}/state/inmemory.py +0 -0
  65. /ommlds/cli/sessions/chat/{chat → agents}/state/storage.py +0 -0
  66. /ommlds/cli/sessions/chat/{interface/bare → agents/tools}/__init__.py +0 -0
  67. /ommlds/cli/sessions/chat/{interface/textual → agents/tools/fs}/__init__.py +0 -0
  68. /ommlds/cli/sessions/chat/{tools → agents/tools}/fs/configs.py +0 -0
  69. /ommlds/cli/sessions/chat/{phases → agents/tools/todo}/__init__.py +0 -0
  70. /ommlds/cli/sessions/chat/{tools → agents/tools}/todo/configs.py +0 -0
  71. /ommlds/cli/sessions/chat/{tools → agents/tools/weather}/__init__.py +0 -0
  72. /ommlds/cli/sessions/chat/{tools → agents/tools}/weather/configs.py +0 -0
  73. /ommlds/cli/sessions/chat/{tools → agents/tools}/weather/inject.py +0 -0
  74. /ommlds/cli/sessions/chat/{tools/fs → agents/user}/__init__.py +0 -0
  75. /ommlds/cli/sessions/chat/{tools/todo → interfaces}/__init__.py +0 -0
  76. /ommlds/cli/sessions/chat/{tools/weather → interfaces/bare}/__init__.py +0 -0
  77. /ommlds/cli/sessions/chat/{interface → interfaces}/base.py +0 -0
  78. /ommlds/cli/sessions/chat/{interface → interfaces}/configs.py +0 -0
  79. /ommlds/cli/sessions/chat/{interface → interfaces}/inject.py +0 -0
  80. {ommlds-0.0.0.dev488.dist-info → ommlds-0.0.0.dev490.dist-info}/WHEEL +0 -0
  81. {ommlds-0.0.0.dev488.dist-info → ommlds-0.0.0.dev490.dist-info}/entry_points.txt +0 -0
  82. {ommlds-0.0.0.dev488.dist-info → ommlds-0.0.0.dev490.dist-info}/licenses/LICENSE +0 -0
  83. {ommlds-0.0.0.dev488.dist-info → ommlds-0.0.0.dev490.dist-info}/top_level.txt +0 -0
@@ -1,8 +1,8 @@
1
1
  import typing as ta
2
2
 
3
- from ..... import minichain as mc
4
- from ....rendering.types import ContentRendering
5
- from .execution import ToolUseExecutor
3
+ from ...... import minichain as mc
4
+ from .....rendering.types import ContentRendering
5
+ from ...agents.tools.execution import ToolUseExecutor
6
6
 
7
7
 
8
8
  ##
@@ -10,9 +10,9 @@ from .configs import TodoToolSetConfig
10
10
 
11
11
 
12
12
  def bind_todo_tools(cfg: TodoToolSetConfig) -> inj.Elements:
13
- from ......minichain.lib.todo.context import TodoContext
14
- from ......minichain.lib.todo.tools.read import todo_read_tool
15
- from ......minichain.lib.todo.tools.write import todo_write_tool
13
+ from .......minichain.lib.todo.context import TodoContext
14
+ from .......minichain.lib.todo.tools.read import todo_read_tool
15
+ from .......minichain.lib.todo.tools.write import todo_write_tool
16
16
 
17
17
  return inj.as_elements(
18
18
  tool_catalog_entries().bind_item_consts(
@@ -1,4 +1,4 @@
1
- from ...... import minichain as mc
1
+ from ....... import minichain as mc
2
2
 
3
3
 
4
4
  ##
@@ -12,5 +12,3 @@ from ...... import minichain as mc
12
12
  class UserConfig:
13
13
  initial_system_content: ta.Optional['mc.Content'] = None
14
14
  initial_user_content: ta.Optional['mc.Content'] = None
15
-
16
- interactive: bool = False
@@ -0,0 +1,40 @@
1
+ from omlish import inject as inj
2
+ from omlish import lang
3
+
4
+ from ...... import minichain as mc
5
+ from ..phases.injection import phase_callbacks
6
+ from ..phases.types import ChatPhase
7
+ from ..phases.types import ChatPhaseCallback
8
+ from .configs import UserConfig
9
+
10
+
11
+ with lang.auto_proxy_import(globals()):
12
+ from .. import agent as _agent
13
+ from ..state import types as _state
14
+
15
+
16
+ ##
17
+
18
+
19
+ def bind_user(cfg: UserConfig = UserConfig()) -> inj.Elements:
20
+ els: list[inj.Elemental] = []
21
+
22
+ if cfg.initial_system_content is not None:
23
+ async def add_initial_system_content(cm: '_state.ChatStateManager') -> None:
24
+ await cm.extend_chat([mc.SystemMessage(cfg.initial_system_content)])
25
+
26
+ els.append(phase_callbacks().bind_item(to_fn=inj.KwargsTarget.of(
27
+ lambda cm: ChatPhaseCallback(ChatPhase.STARTED, lambda: add_initial_system_content(cm)),
28
+ cm=_state.ChatStateManager,
29
+ )))
30
+
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)])
34
+
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],
38
+ )))
39
+
40
+ return inj.as_elements(*els)
@@ -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 .chat.ai.configs import AiConfig
6
- from .chat.state.configs import StateConfig
7
- from .chat.user.configs import UserConfig
8
- from .interface.configs import InterfaceConfig
9
- from .tools.configs import ToolsConfig
4
+ from .agents.configs import AgentConfig
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
- backend: BackendConfig = BackendConfig()
24
- ai: AiConfig = AiConfig()
25
- state: StateConfig = StateConfig()
26
- user: UserConfig = UserConfig()
27
- rendering: RenderingConfig = RenderingConfig()
19
+ agent: AgentConfig = AgentConfig()
28
20
  interface: InterfaceConfig = InterfaceConfig()
29
- tools: ToolsConfig = ToolsConfig()
21
+ rendering: RenderingConfig = RenderingConfig()
@@ -2,23 +2,15 @@ from omlish import dataclasses as dc
2
2
  from omlish import inject as inj
3
3
  from omlish import lang
4
4
 
5
- from ...backends.types import DefaultBackendName
6
5
  from ..base import Session
7
- from .configs import DEFAULT_BACKEND
8
6
  from .configs import ChatConfig
9
7
 
10
8
 
11
9
  with lang.auto_proxy_import(globals()):
12
- from ...backends import inject as _backends
13
10
  from ...rendering import inject as _rendering
14
- from . import driver as _driver
15
11
  from . import session as _session
16
- from .chat.ai import inject as _chat_ai
17
- from .chat.state import inject as _chat_state
18
- from .chat.user import inject as _chat_user
19
- from .interface import inject as _interface
20
- from .phases import inject as _phases
21
- from .tools import inject as _tools
12
+ from .agents import inject as _agents
13
+ from .interfaces import inject as _interfaces
22
14
 
23
15
 
24
16
  ##
@@ -30,27 +22,11 @@ def bind_chat(cfg: ChatConfig) -> inj.Elements:
30
22
  #
31
23
 
32
24
  els.extend([
33
- _backends.bind_backends(cfg.backend),
25
+ _agents.bind_agent(cfg.agent),
34
26
 
35
- _chat_ai.bind_ai(cfg.ai),
36
-
37
- _chat_user.bind_user(cfg.user),
38
-
39
- _chat_state.bind_state(cfg.state),
40
-
41
- _interface.bind_interface(cfg.interface),
42
-
43
- _phases.bind_phases(),
27
+ _interfaces.bind_interface(cfg.interface),
44
28
 
45
29
  _rendering.bind_rendering(cfg.rendering),
46
-
47
- _tools.bind_tools(cfg.tools),
48
- ])
49
-
50
- #
51
-
52
- els.extend([
53
- inj.bind(_driver.ChatDriver, singleton=True),
54
30
  ])
55
31
 
56
32
  #
@@ -62,8 +38,4 @@ def bind_chat(cfg: ChatConfig) -> inj.Elements:
62
38
 
63
39
  #
64
40
 
65
- els.append(inj.bind(DefaultBackendName, to_const=DEFAULT_BACKEND))
66
-
67
- #
68
-
69
41
  return inj.as_elements(*els)
@@ -3,26 +3,36 @@ from omlish import lang
3
3
 
4
4
  from ..base import ChatInterface
5
5
  from ..configs import InterfaceConfig
6
- from .interface import BareChatInterface
7
6
 
8
7
 
9
8
  with lang.auto_proxy_import(globals()):
10
9
  from .....inputs import asyncs as _inputs_asyncs
11
10
  from .....inputs import sync as _inputs_sync
11
+ from . import interactive as _interactive
12
+ from . import oneshot as _oneshot
12
13
 
13
14
 
14
15
  ##
15
16
 
16
17
 
17
18
  def bind_bare(cfg: InterfaceConfig = InterfaceConfig()) -> inj.Elements:
18
- els: list[inj.Elemental] = [
19
- inj.bind(ChatInterface, to_ctor=BareChatInterface, singleton=True),
20
- ]
19
+ els: list[inj.Elemental] = []
21
20
 
22
21
  if cfg.interactive:
22
+ els.extend([
23
+ inj.bind(_interactive.InteractiveBareChatInterface, singleton=True),
24
+ inj.bind(ChatInterface, to_key=_interactive.InteractiveBareChatInterface),
25
+ ])
26
+
23
27
  els.extend([
24
28
  inj.bind(_inputs_sync.SyncStringInput, to_const=_inputs_sync.InputSyncStringInput(use_readline=cfg.use_readline)), # noqa
25
29
  inj.bind(_inputs_asyncs.AsyncStringInput, to_ctor=_inputs_asyncs.ThreadAsyncStringInput, singleton=True),
26
30
  ])
27
31
 
32
+ else:
33
+ els.extend([
34
+ inj.bind(_oneshot.OneshotBareChatInterface, singleton=True),
35
+ inj.bind(ChatInterface, to_key=_oneshot.OneshotBareChatInterface),
36
+ ])
37
+
28
38
  return inj.as_elements(*els)
@@ -0,0 +1,41 @@
1
+ import typing as ta
2
+
3
+ from ...... import minichain as mc
4
+ from .....inputs.asyncs import AsyncStringInput
5
+ from .....inputs.asyncs import SyncAsyncStringInput
6
+ from .....inputs.sync import InputSyncStringInput
7
+ from ...agents.agent import ChatAgent
8
+ from ..base import ChatInterface
9
+
10
+
11
+ ##
12
+
13
+
14
+ class InteractiveBareChatInterface(ChatInterface):
15
+ DEFAULT_STRING_INPUT: ta.ClassVar[AsyncStringInput] = SyncAsyncStringInput(InputSyncStringInput())
16
+
17
+ def __init__(
18
+ self,
19
+ *,
20
+ agent: ChatAgent,
21
+ string_input: AsyncStringInput | None = None,
22
+ ) -> None:
23
+ super().__init__()
24
+
25
+ self._agent = agent
26
+ if string_input is None:
27
+ string_input = self.DEFAULT_STRING_INPUT
28
+ self._string_input = string_input
29
+
30
+ async def run(self) -> None:
31
+ await self._agent.start()
32
+
33
+ while True:
34
+ try:
35
+ s = await self._string_input()
36
+ except EOFError:
37
+ break
38
+
39
+ await self._agent.send_user_messages([mc.UserMessage(s)])
40
+
41
+ await self._agent.stop()
@@ -0,0 +1,21 @@
1
+ from ...agents.agent import ChatAgent
2
+ from ..base import ChatInterface
3
+
4
+
5
+ ##
6
+
7
+
8
+ class OneshotBareChatInterface(ChatInterface):
9
+ def __init__(
10
+ self,
11
+ *,
12
+ agent: ChatAgent,
13
+ ) -> None:
14
+ super().__init__()
15
+
16
+ self._agent = agent
17
+
18
+ async def run(self) -> None:
19
+ await self._agent.start()
20
+
21
+ await self._agent.stop()
@@ -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 .types import UserChatInput
7
+ from ...agents.user.types import UserChatInput
8
8
 
9
9
 
10
10
  ##
@@ -0,0 +1,211 @@
1
+ import asyncio
2
+ import dataclasses as dc
3
+ import io
4
+ import typing as ta
5
+
6
+ from omdev.tui import textual as tx
7
+ from omlish import check
8
+ from omlish import lang
9
+
10
+ from ...... import minichain as mc
11
+ from ...agents.agent import ChatAgent
12
+ from ...agents.events.types import AiMessagesChatEvent
13
+
14
+
15
+ ##
16
+
17
+
18
+ ChatAgentEventQueue = ta.NewType('ChatAgentEventQueue', asyncio.Queue)
19
+
20
+
21
+ ##
22
+
23
+
24
+ class WelcomeMessage(tx.Static):
25
+ def __init__(self, content: str) -> None:
26
+ super().__init__(content)
27
+
28
+ self.add_class('welcome-message')
29
+
30
+
31
+ class UserMessage(tx.Static):
32
+ def __init__(self, content: str) -> None:
33
+ super().__init__(content)
34
+
35
+ self.add_class('user-message')
36
+
37
+
38
+ class AiMessage(tx.Static):
39
+ def __init__(self, content: str) -> None:
40
+ super().__init__(content)
41
+
42
+ self.add_class('ai-message')
43
+
44
+
45
+ ##
46
+
47
+
48
+ class InputTextArea(tx.TextArea):
49
+ @dc.dataclass()
50
+ class Submitted(tx.Message):
51
+ text: str
52
+
53
+ def __init__(self, **kwargs: ta.Any) -> None:
54
+ super().__init__(**kwargs)
55
+
56
+ async def _on_key(self, event: tx.Key) -> None:
57
+ if event.key == 'enter':
58
+ event.prevent_default()
59
+ event.stop()
60
+
61
+ if text := self.text.strip():
62
+ self.post_message(self.Submitted(text))
63
+
64
+ else:
65
+ await super()._on_key(event)
66
+
67
+
68
+ ##
69
+
70
+
71
+ @lang.cached_function
72
+ def _read_app_css() -> str:
73
+ tcss_rsrcs = [
74
+ rsrc
75
+ for rsrc in lang.get_relative_resources('.styles', globals=globals()).values()
76
+ if rsrc.name.endswith('.tcss')
77
+ ]
78
+
79
+ out = io.StringIO()
80
+
81
+ for i, rsrc in enumerate(tcss_rsrcs):
82
+ if i:
83
+ out.write('\n\n')
84
+
85
+ out.write(f'/* {rsrc.name} */\n')
86
+ out.write('\n')
87
+
88
+ out.write(rsrc.read_text().strip())
89
+ out.write('\n')
90
+
91
+ return out.getvalue()
92
+
93
+
94
+ #
95
+
96
+
97
+ class ChatApp(tx.App):
98
+ def __init__(
99
+ self,
100
+ *,
101
+ agent: ChatAgent,
102
+ event_queue: ChatAgentEventQueue,
103
+ ) -> None:
104
+ super().__init__()
105
+
106
+ self._agent = agent
107
+ self._event_queue = event_queue
108
+
109
+ CSS: ta.ClassVar[str] = _read_app_css()
110
+
111
+ ENABLE_COMMAND_PALETTE: ta.ClassVar[bool] = False
112
+
113
+ #
114
+
115
+ def compose(self) -> tx.ComposeResult:
116
+ with tx.VerticalScroll(id='messages-scroll'):
117
+ yield tx.Static(id='messages-container')
118
+
119
+ with tx.Static(id='input-outer'):
120
+ with tx.Vertical(id='input-vertical'):
121
+ with tx.Vertical(id='input-vertical2'):
122
+ with tx.Horizontal(id='input-horizontal'):
123
+ yield tx.Static('>', id='input-glyph')
124
+ yield InputTextArea(placeholder='...', id='input')
125
+
126
+ #
127
+
128
+ def _get_input_text_area(self) -> InputTextArea:
129
+ return self.query_one('#input', InputTextArea)
130
+
131
+ def _get_messages_container(self) -> tx.Static:
132
+ return self.query_one('#messages-container', tx.Static)
133
+
134
+ #
135
+
136
+ _pending_mount_messages: list[tx.Widget] | None = None
137
+
138
+ async def _enqueue_mount_messages(self, *messages: tx.Widget) -> None:
139
+ if (lst := self._pending_mount_messages) is None:
140
+ lst = self._pending_mount_messages = []
141
+
142
+ lst.extend(messages)
143
+
144
+ async def _mount_messages(self, *messages: tx.Widget) -> None:
145
+ msg_ctr = self._get_messages_container()
146
+
147
+ for msg in [*(self._pending_mount_messages or []), *messages]:
148
+ await msg_ctr.mount(msg)
149
+
150
+ self._pending_mount_messages = None
151
+
152
+ self.call_after_refresh(lambda: msg_ctr.scroll_end(animate=False))
153
+
154
+ #
155
+
156
+ _event_queue_task: asyncio.Task[None] | None = None
157
+
158
+ async def _event_queue_task_main(self) -> None:
159
+ while True:
160
+ ev = await self._event_queue.get()
161
+ if ev is None:
162
+ break
163
+
164
+ if isinstance(ev, AiMessagesChatEvent):
165
+ wx: list[tx.Widget] = []
166
+
167
+ for ai_msg in ev.chat:
168
+ if isinstance(ai_msg, mc.AiMessage):
169
+ wx.append(
170
+ AiMessage(
171
+ check.isinstance(ai_msg.c, str),
172
+ ),
173
+ )
174
+
175
+ if wx:
176
+ await self._enqueue_mount_messages(*wx)
177
+ self.call_later(self._mount_messages)
178
+
179
+ #
180
+
181
+ async def on_mount(self) -> None:
182
+ check.state(self._event_queue_task is None)
183
+ self._event_queue_task = asyncio.create_task(self._event_queue_task_main())
184
+
185
+ await self._agent.start()
186
+
187
+ self._get_input_text_area().focus()
188
+
189
+ await self._mount_messages(
190
+ WelcomeMessage(
191
+ 'Hello!',
192
+ ),
193
+ )
194
+
195
+ async def on_unmount(self) -> None:
196
+ await self._agent.stop()
197
+
198
+ if (eqt := self._event_queue_task) is not None:
199
+ await self._event_queue.put(None)
200
+ await eqt
201
+
202
+ async def on_input_text_area_submitted(self, event: InputTextArea.Submitted) -> None:
203
+ self._get_input_text_area().clear()
204
+
205
+ await self._mount_messages(
206
+ UserMessage(
207
+ event.text,
208
+ ),
209
+ )
210
+
211
+ await self._agent.send_user_messages([mc.UserMessage(event.text)])
@@ -0,0 +1,43 @@
1
+ """
2
+ FIXME:
3
+ - too lazy to lazy import guts like every other proper inject module lol >_<
4
+ """
5
+ import asyncio
6
+
7
+ from omlish import inject as inj
8
+
9
+ from ...agents.events.injection import event_callbacks
10
+ from ..base import ChatInterface
11
+ from .app import ChatAgentEventQueue
12
+ from .app import ChatApp
13
+ from .interface import TextualChatInterface
14
+
15
+
16
+ ##
17
+
18
+
19
+ def bind_textual() -> inj.Elements:
20
+ els: list[inj.Elemental] = [
21
+ inj.bind(ChatInterface, to_ctor=TextualChatInterface, singleton=True),
22
+ ]
23
+
24
+ #
25
+
26
+ els.extend([
27
+ inj.bind(ChatApp, singleton=True),
28
+ ])
29
+
30
+ #
31
+
32
+ els.extend([
33
+ inj.bind(ChatAgentEventQueue, to_const=asyncio.Queue()),
34
+
35
+ event_callbacks().bind_item(to_fn=inj.KwargsTarget.of(
36
+ lambda eq: lambda ev: eq.put(ev),
37
+ eq=ChatAgentEventQueue,
38
+ )),
39
+ ])
40
+
41
+ #
42
+
43
+ return inj.as_elements(*els)
@@ -1,4 +1,3 @@
1
- from ...driver import ChatDriver
2
1
  from ..base import ChatInterface
3
2
  from .app import ChatApp
4
3
 
@@ -10,12 +9,10 @@ class TextualChatInterface(ChatInterface):
10
9
  def __init__(
11
10
  self,
12
11
  *,
13
- driver: ChatDriver,
14
12
  app: ChatApp,
15
13
  ) -> None:
16
14
  super().__init__()
17
15
 
18
- self._driver = driver
19
16
  self._app = app
20
17
 
21
18
  async def run(self) -> None:
@@ -0,0 +1,51 @@
1
+ #input-outer {
2
+ width: 100%;
3
+ height: auto;
4
+ }
5
+
6
+ #input-vertical {
7
+ width: 100%;
8
+ height: auto;
9
+
10
+ margin: 0 2 1 2;
11
+
12
+ padding: 0;
13
+ }
14
+
15
+ #input-vertical2 {
16
+ width: 100%;
17
+ height: auto;
18
+
19
+ border: round $foreground-muted;
20
+
21
+ padding: 0 1;
22
+ }
23
+
24
+ #input-horizontal {
25
+ width: 100%;
26
+ height: auto;
27
+ }
28
+
29
+ #input-glyph {
30
+ width: auto;
31
+
32
+ padding: 0 1 0 0;
33
+
34
+ background: transparent;
35
+ color: $primary;
36
+
37
+ text-style: bold;
38
+ }
39
+
40
+ #input {
41
+ width: 1fr;
42
+ height: auto;
43
+ max-height: 16;
44
+
45
+ border: none;
46
+
47
+ padding: 0;
48
+
49
+ background: transparent;
50
+ color: $text;
51
+ }
@@ -0,0 +1,33 @@
1
+ #messages-scroll {
2
+ width: 100%;
3
+ height: 1fr;
4
+
5
+ padding: 0 2 0 2;
6
+ }
7
+
8
+ #messages-container {
9
+ height: auto;
10
+ width: 100%;
11
+
12
+ margin-top: 1;
13
+ margin-bottom: 0;
14
+
15
+ layout: stream;
16
+ text-align: left;
17
+ }
18
+
19
+ .welcome-message {
20
+ margin: 1;
21
+
22
+ border: round;
23
+
24
+ padding: 1;
25
+
26
+ text-align: center;
27
+ }
28
+
29
+ .user-message {
30
+ }
31
+
32
+ .ai-message {
33
+ }
@@ -4,7 +4,7 @@ from omlish import dataclasses as dc
4
4
 
5
5
  from ..base import Session
6
6
  from .configs import ChatConfig
7
- from .interface.base import ChatInterface
7
+ from .interfaces.base import ChatInterface
8
8
 
9
9
 
10
10
  ##
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ommlds
3
- Version: 0.0.0.dev488
3
+ Version: 0.0.0.dev490
4
4
  Summary: ommlds
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -14,9 +14,9 @@ Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Python: >=3.13
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
- Requires-Dist: omlish==0.0.0.dev488
17
+ Requires-Dist: omlish==0.0.0.dev490
18
18
  Provides-Extra: all
19
- Requires-Dist: omdev==0.0.0.dev488; extra == "all"
19
+ Requires-Dist: omdev==0.0.0.dev490; extra == "all"
20
20
  Requires-Dist: llama-cpp-python~=0.3; extra == "all"
21
21
  Requires-Dist: mlx~=0.30; sys_platform == "darwin" and extra == "all"
22
22
  Requires-Dist: mlx-lm~=0.28; sys_platform == "darwin" and extra == "all"
@@ -38,7 +38,7 @@ Requires-Dist: mwparserfromhell~=0.7; extra == "all"
38
38
  Requires-Dist: wikitextparser~=0.56; extra == "all"
39
39
  Requires-Dist: lxml>=5.3; python_version < "3.13" and extra == "all"
40
40
  Provides-Extra: omdev
41
- Requires-Dist: omdev==0.0.0.dev488; extra == "omdev"
41
+ Requires-Dist: omdev==0.0.0.dev490; extra == "omdev"
42
42
  Provides-Extra: backends
43
43
  Requires-Dist: llama-cpp-python~=0.3; extra == "backends"
44
44
  Requires-Dist: mlx~=0.30; sys_platform == "darwin" and extra == "backends"