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.
- ommlds/cli/_dataclasses.py +657 -328
- ommlds/cli/main.py +74 -42
- ommlds/cli/sessions/chat/agents/agent.py +49 -0
- ommlds/cli/sessions/chat/{chat → agents}/ai/configs.py +3 -1
- ommlds/cli/sessions/chat/agents/ai/events.py +57 -0
- ommlds/cli/sessions/chat/{chat → agents}/ai/inject.py +7 -2
- ommlds/cli/sessions/chat/{chat → agents}/ai/rendering.py +1 -1
- ommlds/cli/sessions/chat/{chat → agents}/ai/services.py +1 -1
- ommlds/cli/sessions/chat/{chat → agents}/ai/tools.py +1 -1
- ommlds/cli/sessions/chat/{chat → agents}/ai/types.py +9 -0
- ommlds/cli/sessions/chat/agents/configs.py +25 -0
- ommlds/cli/sessions/chat/agents/events/inject.py +27 -0
- ommlds/cli/sessions/chat/agents/events/injection.py +14 -0
- ommlds/cli/sessions/chat/agents/events/manager.py +16 -0
- ommlds/cli/sessions/chat/agents/events/types.py +38 -0
- ommlds/cli/sessions/chat/agents/inject.py +62 -0
- ommlds/cli/sessions/chat/{chat → agents}/state/inject.py +3 -3
- ommlds/cli/sessions/chat/{chat → agents}/state/types.py +1 -1
- ommlds/cli/sessions/chat/{tools → agents/tools}/configs.py +3 -1
- ommlds/cli/sessions/chat/{tools → agents/tools}/confirmation.py +1 -1
- ommlds/cli/sessions/chat/{tools → agents/tools}/execution.py +1 -1
- ommlds/cli/sessions/chat/{tools → agents/tools}/fs/inject.py +3 -3
- ommlds/cli/sessions/chat/{tools → agents/tools}/inject.py +8 -4
- ommlds/cli/sessions/chat/{tools → agents/tools}/injection.py +1 -1
- ommlds/cli/sessions/chat/{tools → agents/tools}/rendering.py +3 -3
- ommlds/cli/sessions/chat/{tools → agents/tools}/todo/inject.py +3 -3
- ommlds/cli/sessions/chat/{tools → agents/tools}/weather/tools.py +1 -1
- ommlds/cli/sessions/chat/{chat → agents}/user/configs.py +0 -2
- ommlds/cli/sessions/chat/agents/user/inject.py +40 -0
- ommlds/cli/sessions/chat/configs.py +4 -12
- ommlds/cli/sessions/chat/inject.py +4 -32
- ommlds/cli/sessions/chat/{interface → interfaces}/bare/inject.py +14 -4
- ommlds/cli/sessions/chat/interfaces/bare/interactive.py +41 -0
- ommlds/cli/sessions/chat/interfaces/bare/oneshot.py +21 -0
- ommlds/cli/sessions/chat/{chat/user/interactive.py → interfaces/bare/user.py} +1 -1
- ommlds/cli/sessions/chat/interfaces/textual/__init__.py +0 -0
- ommlds/cli/sessions/chat/interfaces/textual/app.py +211 -0
- ommlds/cli/sessions/chat/interfaces/textual/inject.py +43 -0
- ommlds/cli/sessions/chat/{interface → interfaces}/textual/interface.py +0 -3
- ommlds/cli/sessions/chat/interfaces/textual/styles/__init__.py +0 -0
- ommlds/cli/sessions/chat/interfaces/textual/styles/input.tcss +51 -0
- ommlds/cli/sessions/chat/interfaces/textual/styles/messages.tcss +33 -0
- ommlds/cli/sessions/chat/session.py +1 -1
- {ommlds-0.0.0.dev488.dist-info → ommlds-0.0.0.dev490.dist-info}/METADATA +4 -4
- {ommlds-0.0.0.dev488.dist-info → ommlds-0.0.0.dev490.dist-info}/RECORD +76 -66
- ommlds/cli/sessions/chat/chat/user/inject.py +0 -55
- 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/interface.py +0 -19
- ommlds/cli/sessions/chat/interface/textual/app.py +0 -14
- ommlds/cli/sessions/chat/interface/textual/inject.py +0 -20
- /ommlds/cli/sessions/chat/{chat → agents}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{chat → agents}/ai/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{chat → agents}/ai/injection.py +0 -0
- /ommlds/cli/sessions/chat/{chat/state → agents/events}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{chat/user → agents/phases}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{phases → agents/phases}/inject.py +0 -0
- /ommlds/cli/sessions/chat/{phases → agents/phases}/injection.py +0 -0
- /ommlds/cli/sessions/chat/{phases → agents/phases}/manager.py +0 -0
- /ommlds/cli/sessions/chat/{phases → agents/phases}/types.py +0 -0
- /ommlds/cli/sessions/chat/{interface → agents/state}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{chat → agents}/state/configs.py +0 -0
- /ommlds/cli/sessions/chat/{chat → agents}/state/inmemory.py +0 -0
- /ommlds/cli/sessions/chat/{chat → agents}/state/storage.py +0 -0
- /ommlds/cli/sessions/chat/{interface/bare → agents/tools}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{interface/textual → agents/tools/fs}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{tools → agents/tools}/fs/configs.py +0 -0
- /ommlds/cli/sessions/chat/{phases → agents/tools/todo}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{tools → agents/tools}/todo/configs.py +0 -0
- /ommlds/cli/sessions/chat/{tools → agents/tools/weather}/__init__.py +0 -0
- /ommlds/cli/sessions/chat/{tools → agents/tools}/weather/configs.py +0 -0
- /ommlds/cli/sessions/chat/{tools → agents/tools}/weather/inject.py +0 -0
- /ommlds/cli/sessions/chat/{tools/fs → agents/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}/configs.py +0 -0
- /ommlds/cli/sessions/chat/{interface → interfaces}/inject.py +0 -0
- {ommlds-0.0.0.dev488.dist-info → ommlds-0.0.0.dev490.dist-info}/WHEEL +0 -0
- {ommlds-0.0.0.dev488.dist-info → ommlds-0.0.0.dev490.dist-info}/entry_points.txt +0 -0
- {ommlds-0.0.0.dev488.dist-info → ommlds-0.0.0.dev490.dist-info}/licenses/LICENSE +0 -0
- {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
|
|
4
|
-
from
|
|
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
|
|
14
|
-
from
|
|
15
|
-
from
|
|
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(
|
|
@@ -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 .
|
|
6
|
-
from .
|
|
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
|
-
|
|
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
|
-
|
|
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 .
|
|
17
|
-
from .
|
|
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
|
-
|
|
25
|
+
_agents.bind_agent(cfg.agent),
|
|
34
26
|
|
|
35
|
-
|
|
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
|
##
|
|
File without changes
|
|
@@ -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:
|
|
File without changes
|
|
@@ -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
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ommlds
|
|
3
|
-
Version: 0.0.0.
|
|
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.
|
|
17
|
+
Requires-Dist: omlish==0.0.0.dev490
|
|
18
18
|
Provides-Extra: all
|
|
19
|
-
Requires-Dist: omdev==0.0.0.
|
|
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.
|
|
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"
|