ommlds 0.0.0.dev462__py3-none-any.whl → 0.0.0.dev464__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.

Potentially problematic release.


This version of ommlds might be problematic. Click here for more details.

Files changed (67) hide show
  1. ommlds/backends/mlx/loading.py +58 -1
  2. ommlds/cli/inject.py +0 -5
  3. ommlds/cli/main.py +26 -38
  4. ommlds/cli/sessions/chat/backends/catalog.py +56 -0
  5. ommlds/cli/sessions/chat/backends/inject.py +37 -0
  6. ommlds/cli/sessions/chat/backends/injection.py +16 -0
  7. ommlds/cli/sessions/chat/backends/types.py +36 -0
  8. ommlds/cli/sessions/chat/chat/__init__.py +0 -0
  9. ommlds/cli/sessions/chat/chat/ai/__init__.py +0 -0
  10. ommlds/cli/sessions/chat/chat/ai/inject.py +81 -0
  11. ommlds/cli/sessions/chat/chat/ai/injection.py +14 -0
  12. ommlds/cli/sessions/chat/chat/ai/rendering.py +70 -0
  13. ommlds/cli/sessions/chat/chat/ai/services.py +81 -0
  14. ommlds/cli/sessions/chat/chat/ai/tools.py +44 -0
  15. ommlds/cli/sessions/chat/chat/ai/types.py +28 -0
  16. ommlds/cli/sessions/chat/chat/state/__init__.py +0 -0
  17. ommlds/cli/sessions/chat/chat/state/inject.py +40 -0
  18. ommlds/cli/sessions/chat/chat/state/inmemory.py +34 -0
  19. ommlds/cli/sessions/chat/chat/state/storage.py +53 -0
  20. ommlds/cli/sessions/chat/chat/state/types.py +38 -0
  21. ommlds/cli/sessions/chat/chat/user/__init__.py +0 -0
  22. ommlds/cli/sessions/chat/chat/user/inject.py +61 -0
  23. ommlds/cli/sessions/chat/chat/user/interactive.py +29 -0
  24. ommlds/cli/sessions/chat/chat/user/oneshot.py +25 -0
  25. ommlds/cli/sessions/chat/chat/user/types.py +15 -0
  26. ommlds/cli/sessions/chat/configs.py +36 -0
  27. ommlds/cli/sessions/chat/content/__init__.py +0 -0
  28. ommlds/cli/sessions/chat/content/messages.py +34 -0
  29. ommlds/cli/sessions/chat/content/strings.py +42 -0
  30. ommlds/cli/sessions/chat/driver.py +43 -0
  31. ommlds/cli/sessions/chat/inject.py +40 -66
  32. ommlds/cli/sessions/chat/phases/__init__.py +0 -0
  33. ommlds/cli/sessions/chat/phases/inject.py +27 -0
  34. ommlds/cli/sessions/chat/phases/injection.py +14 -0
  35. ommlds/cli/sessions/chat/phases/manager.py +29 -0
  36. ommlds/cli/sessions/chat/phases/types.py +29 -0
  37. ommlds/cli/sessions/chat/rendering/__init__.py +0 -0
  38. ommlds/cli/sessions/chat/rendering/inject.py +32 -0
  39. ommlds/cli/sessions/chat/rendering/markdown.py +52 -0
  40. ommlds/cli/sessions/chat/rendering/raw.py +73 -0
  41. ommlds/cli/sessions/chat/rendering/types.py +21 -0
  42. ommlds/cli/sessions/chat/session.py +27 -0
  43. ommlds/cli/sessions/chat/tools/__init__.py +0 -0
  44. ommlds/cli/sessions/chat/tools/confirmation.py +46 -0
  45. ommlds/cli/sessions/chat/tools/execution.py +66 -0
  46. ommlds/cli/sessions/chat/tools/inject.py +145 -0
  47. ommlds/cli/sessions/chat/tools/injection.py +29 -0
  48. ommlds/cli/sessions/chat/tools/rendering.py +58 -0
  49. ommlds/cli/{tools → sessions/chat/tools}/weather.py +1 -1
  50. ommlds/cli/sessions/inject.py +3 -3
  51. ommlds/cli/state.py +40 -23
  52. {ommlds-0.0.0.dev462.dist-info → ommlds-0.0.0.dev464.dist-info}/METADATA +3 -3
  53. {ommlds-0.0.0.dev462.dist-info → ommlds-0.0.0.dev464.dist-info}/RECORD +58 -23
  54. ommlds/cli/sessions/chat/base.py +0 -42
  55. ommlds/cli/sessions/chat/code.py +0 -125
  56. ommlds/cli/sessions/chat/interactive.py +0 -70
  57. ommlds/cli/sessions/chat/printing.py +0 -126
  58. ommlds/cli/sessions/chat/prompt.py +0 -161
  59. ommlds/cli/sessions/chat/state.py +0 -110
  60. ommlds/cli/sessions/chat/tools.py +0 -97
  61. ommlds/cli/tools/config.py +0 -14
  62. ommlds/cli/tools/inject.py +0 -75
  63. /ommlds/cli/{tools → sessions/chat/backends}/__init__.py +0 -0
  64. {ommlds-0.0.0.dev462.dist-info → ommlds-0.0.0.dev464.dist-info}/WHEEL +0 -0
  65. {ommlds-0.0.0.dev462.dist-info → ommlds-0.0.0.dev464.dist-info}/entry_points.txt +0 -0
  66. {ommlds-0.0.0.dev462.dist-info → ommlds-0.0.0.dev464.dist-info}/licenses/LICENSE +0 -0
  67. {ommlds-0.0.0.dev462.dist-info → ommlds-0.0.0.dev464.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,40 @@
1
+ import typing as ta
2
+
3
+ from omlish import inject as inj
4
+ from omlish import lang
5
+
6
+ from ...phases.injection import phase_callbacks
7
+ from ...phases.types import ChatPhase
8
+ from ...phases.types import ChatPhaseCallback
9
+
10
+
11
+ with lang.auto_proxy_import(globals()):
12
+ from . import inmemory as _inmemory
13
+ from . import storage as _storage
14
+ from . import types as _types
15
+
16
+
17
+ ##
18
+
19
+
20
+ def bind_state(
21
+ *,
22
+ state: ta.Literal['new', 'continue', 'ephemeral'] = 'continue',
23
+ ) -> inj.Elements:
24
+ els: list[inj.Elemental] = []
25
+
26
+ if state in ('continue', 'new'):
27
+ els.append(inj.bind(_types.ChatStateManager, to_ctor=_storage.StateStorageChatStateManager, singleton=True))
28
+
29
+ if state == 'new':
30
+ els.append(phase_callbacks().bind_item(to_fn=lang.typed_lambda(cm=_types.ChatStateManager)(
31
+ lambda cm: ChatPhaseCallback(ChatPhase.STARTING, cm.clear_state),
32
+ )))
33
+
34
+ elif state == 'ephemeral':
35
+ els.append(inj.bind(_types.ChatStateManager, to_ctor=_inmemory.InMemoryChatStateManager, singleton=True))
36
+
37
+ else:
38
+ raise TypeError(state)
39
+
40
+ return inj.as_elements(*els)
@@ -0,0 +1,34 @@
1
+ import dataclasses as dc
2
+
3
+ from omlish import lang
4
+
5
+ from ...... import minichain as mc
6
+ from .types import ChatState
7
+ from .types import ChatStateManager
8
+
9
+
10
+ ##
11
+
12
+
13
+ class InMemoryChatStateManager(ChatStateManager):
14
+ def __init__(self, initial_state: ChatState | None = None) -> None:
15
+ super().__init__()
16
+
17
+ if initial_state is None:
18
+ initial_state = ChatState()
19
+ self._state = initial_state
20
+
21
+ async def get_state(self) -> ChatState:
22
+ return self._state
23
+
24
+ async def clear_state(self) -> ChatState:
25
+ self._state = ChatState()
26
+ return self._state
27
+
28
+ async def extend_chat(self, chat_additions: 'mc.Chat') -> ChatState:
29
+ self._state = dc.replace(
30
+ self._state,
31
+ chat=[*self._state.chat, *chat_additions],
32
+ updated_at=lang.utcnow(),
33
+ )
34
+ return self._state
@@ -0,0 +1,53 @@
1
+ import dataclasses as dc
2
+
3
+ from omlish import check
4
+ from omlish import lang
5
+
6
+ from ...... import minichain as mc
7
+ from .....state import StateStorage
8
+ from .types import ChatState
9
+ from .types import ChatStateManager
10
+
11
+
12
+ ##
13
+
14
+
15
+ class StateStorageChatStateManager(ChatStateManager):
16
+ def __init__(
17
+ self,
18
+ *,
19
+ storage: StateStorage,
20
+ key: str = 'chat',
21
+ ) -> None:
22
+ super().__init__()
23
+
24
+ self._storage = storage
25
+ self._key = check.non_empty_str(key)
26
+
27
+ self._state: ChatState | None = None
28
+
29
+ async def get_state(self) -> ChatState:
30
+ if self._state is not None:
31
+ return self._state
32
+ state: ChatState | None = await self._storage.load_state(self._key, ChatState)
33
+ if state is None:
34
+ state = ChatState()
35
+ self._state = state
36
+ return state
37
+
38
+ async def clear_state(self) -> ChatState:
39
+ state = ChatState()
40
+ await self._storage.save_state(self._key, state, ChatState)
41
+ self._state = state
42
+ return state
43
+
44
+ async def extend_chat(self, chat_additions: 'mc.Chat') -> ChatState:
45
+ state = await self.get_state()
46
+ state = dc.replace(
47
+ state,
48
+ chat=[*state.chat, *chat_additions],
49
+ updated_at=lang.utcnow(),
50
+ )
51
+ await self._storage.save_state(self._key, state, ChatState)
52
+ self._state = state
53
+ return state
@@ -0,0 +1,38 @@
1
+ import abc
2
+ import dataclasses as dc
3
+ import datetime
4
+ import typing as ta
5
+
6
+ from omlish import lang
7
+
8
+ from ...... import minichain as mc
9
+
10
+
11
+ ##
12
+
13
+
14
+ @dc.dataclass(frozen=True)
15
+ class ChatState:
16
+ name: str | None = None
17
+
18
+ created_at: datetime.datetime = dc.field(default_factory=lang.utcnow)
19
+ updated_at: datetime.datetime = dc.field(default_factory=lang.utcnow)
20
+
21
+ chat: mc.Chat = ()
22
+
23
+
24
+ ##
25
+
26
+
27
+ class ChatStateManager(lang.Abstract):
28
+ @abc.abstractmethod
29
+ def get_state(self) -> ta.Awaitable[ChatState]:
30
+ raise NotImplementedError
31
+
32
+ @abc.abstractmethod
33
+ def clear_state(self) -> ta.Awaitable[ChatState]:
34
+ raise NotImplementedError
35
+
36
+ @abc.abstractmethod
37
+ def extend_chat(self, chat_additions: 'mc.Chat') -> ta.Awaitable[ChatState]:
38
+ raise NotImplementedError
File without changes
@@ -0,0 +1,61 @@
1
+ import typing as ta
2
+
3
+ from omlish import inject as inj
4
+ from omlish import lang
5
+
6
+ from ...... import minichain as mc
7
+ from ...phases.injection import phase_callbacks
8
+ from ...phases.types import ChatPhase
9
+ from ...phases.types import ChatPhaseCallback
10
+
11
+
12
+ with lang.auto_proxy_import(globals()):
13
+ from ..state import types as _state
14
+ from . import interactive as _interactive
15
+ from . import oneshot as _oneshot
16
+ from . import types as _types
17
+
18
+
19
+ ##
20
+
21
+
22
+ def bind_user(
23
+ *,
24
+ initial_system_content: ta.Optional['mc.Content'] = None,
25
+ initial_user_content: ta.Optional['mc.Content'] = None,
26
+ interactive: bool = False,
27
+ ) -> inj.Elements:
28
+ els: list[inj.Elemental] = []
29
+
30
+ # FIXME: barf
31
+ if initial_system_content is not None:
32
+ async def add_initial_system_content(cm: '_state.ChatStateManager') -> None:
33
+ await cm.extend_chat([mc.SystemMessage(initial_system_content)])
34
+
35
+ els.append(phase_callbacks().bind_item(to_fn=lang.typed_lambda(cm=_state.ChatStateManager)(
36
+ lambda cm: ChatPhaseCallback(ChatPhase.STARTED, lambda: add_initial_system_content(cm)),
37
+ )))
38
+
39
+ if interactive:
40
+ if initial_user_content is not None:
41
+ async def add_initial_user_content(cm: '_state.ChatStateManager') -> None:
42
+ await cm.extend_chat([mc.UserMessage(initial_user_content)])
43
+
44
+ els.append(phase_callbacks().bind_item(to_fn=lang.typed_lambda(cm=_state.ChatStateManager)(
45
+ lambda cm: ChatPhaseCallback(ChatPhase.STARTED, lambda: add_initial_user_content(cm)),
46
+ )))
47
+
48
+ raise NotImplementedError
49
+
50
+ els.append(inj.bind(_types.UserChatInput, to_ctor=_interactive.InteractiveUserChatInput, singleton=True))
51
+
52
+ else:
53
+ if initial_user_content is None:
54
+ raise ValueError('Initial user content is required for non-interactive chat')
55
+
56
+ els.extend([
57
+ inj.bind(_oneshot.OneshotUserChatInputInitialChat, to_const=[mc.UserMessage(initial_user_content)]),
58
+ inj.bind(_types.UserChatInput, to_ctor=_oneshot.OneshotUserChatInput, singleton=True),
59
+ ])
60
+
61
+ return inj.as_elements(*els)
@@ -0,0 +1,29 @@
1
+ import functools
2
+ import typing as ta
3
+
4
+ from omlish import lang
5
+
6
+ from ...... import minichain as mc
7
+ from .types import UserChatInput
8
+
9
+
10
+ ##
11
+
12
+
13
+ class InteractiveUserChatInput(UserChatInput):
14
+ def __init__(
15
+ self,
16
+ string_input: ta.Callable[[], ta.Awaitable[str]] | None = None,
17
+ ) -> None:
18
+ super().__init__()
19
+
20
+ if string_input is None:
21
+ string_input = lang.as_async(functools.partial(input, '> '))
22
+ self._string_input = string_input
23
+
24
+ async def get_next_user_messages(self) -> 'mc.UserChat':
25
+ try:
26
+ s = await self._string_input()
27
+ except EOFError:
28
+ return []
29
+ return [mc.UserMessage(s)]
@@ -0,0 +1,25 @@
1
+ import typing as ta
2
+
3
+ from ...... import minichain as mc
4
+ from .types import UserChatInput
5
+
6
+
7
+ ##
8
+
9
+
10
+ OneshotUserChatInputInitialChat = ta.NewType('OneshotUserChatInputInitialChat', mc.UserChat)
11
+
12
+
13
+ class OneshotUserChatInput(UserChatInput):
14
+ def __init__(
15
+ self,
16
+ initial_chat: OneshotUserChatInputInitialChat,
17
+ ) -> None:
18
+ super().__init__()
19
+
20
+ self._pending_chat: mc.UserChat | None = initial_chat
21
+
22
+ async def get_next_user_messages(self) -> 'mc.UserChat':
23
+ ret = self._pending_chat
24
+ self._pending_chat = None
25
+ return ret or []
@@ -0,0 +1,15 @@
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 UserChatInput(lang.Abstract):
13
+ @abc.abstractmethod
14
+ def get_next_user_messages(self) -> ta.Awaitable['mc.UserChat']:
15
+ raise NotImplementedError
@@ -0,0 +1,36 @@
1
+ import dataclasses as dc
2
+ import typing as ta
3
+
4
+ from .... import minichain as mc
5
+
6
+
7
+ ##
8
+
9
+
10
+ DEFAULT_CHAT_MODEL_BACKEND = 'openai'
11
+
12
+
13
+ ##
14
+
15
+
16
+ @dc.dataclass(frozen=True)
17
+ class ChatConfig:
18
+ _: dc.KW_ONLY
19
+
20
+ backend: str | None = None
21
+ model_name: str | None = None
22
+
23
+ state: ta.Literal['new', 'continue', 'ephemeral'] = 'continue'
24
+
25
+ initial_system_content: ta.Optional['mc.Content'] = None
26
+ initial_user_content: ta.Optional['mc.Content'] = None
27
+ interactive: bool = False
28
+
29
+ silent: bool = False
30
+ markdown: bool = False
31
+
32
+ stream: bool = False
33
+
34
+ enable_tools: bool = False
35
+ enabled_tools: ta.AbstractSet[str] | None = None
36
+ dangerous_no_tool_confirmation: bool = False
File without changes
@@ -0,0 +1,34 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+ from omlish import check
5
+ from omlish import lang
6
+
7
+ from ..... import minichain as mc
8
+
9
+
10
+ ##
11
+
12
+
13
+ class MessageContentExtractor(lang.Abstract):
14
+ @abc.abstractmethod
15
+ def extract_message_content(self, message: 'mc.Message') -> ta.Optional['mc.Content']:
16
+ raise NotImplementedError
17
+
18
+
19
+ class MessageContentExtractorImpl(MessageContentExtractor):
20
+ def extract_message_content(self, message: 'mc.Message') -> ta.Optional['mc.Content']:
21
+ if isinstance(message, (mc.SystemMessage, mc.UserMessage, mc.AiMessage)):
22
+ if message.c is not None:
23
+ return check.isinstance(message.c, str)
24
+ else:
25
+ return None
26
+
27
+ elif isinstance(message, mc.ToolUseMessage):
28
+ return None
29
+
30
+ elif isinstance(message, mc.ToolUseResultMessage):
31
+ return check.isinstance(message.tur.c, str)
32
+
33
+ else:
34
+ raise TypeError(message)
@@ -0,0 +1,42 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+ from omlish import lang
5
+ from omlish.formats import json
6
+
7
+ from ..... import minichain as mc
8
+
9
+
10
+ ##
11
+
12
+
13
+ class ContentStringifier(lang.Abstract):
14
+ @abc.abstractmethod
15
+ def stringify_content(self, content: 'mc.Content') -> str | None:
16
+ raise NotImplementedError
17
+
18
+
19
+ class ContentStringifierImpl(ContentStringifier):
20
+ def stringify_content(self, content: 'mc.Content') -> str | None:
21
+ if isinstance(content, str):
22
+ return content
23
+
24
+ elif isinstance(content, mc.JsonContent):
25
+ return json.dumps_pretty(content.v)
26
+
27
+ else:
28
+ raise TypeError(content)
29
+
30
+
31
+ class HasContentStringifier(lang.Abstract):
32
+ def __init__(
33
+ self,
34
+ *args: ta.Any,
35
+ content_stringifier: ContentStringifier | None = None,
36
+ **kwargs: ta.Any,
37
+ ) -> None:
38
+ super().__init__(*args, **kwargs)
39
+
40
+ if content_stringifier is None:
41
+ content_stringifier = ContentStringifierImpl()
42
+ self._content_stringifier = content_stringifier
@@ -0,0 +1,43 @@
1
+ from .chat.ai.types import AiChatGenerator
2
+ from .chat.state.types import ChatStateManager
3
+ from .chat.user.types import UserChatInput
4
+ from .phases.manager import ChatPhaseManager
5
+ from .phases.types import ChatPhase
6
+
7
+
8
+ ##
9
+
10
+
11
+ class ChatDriver:
12
+ def __init__(
13
+ self,
14
+ *,
15
+ phases: ChatPhaseManager,
16
+ ai_chat_generator: AiChatGenerator,
17
+ user_chat_input: UserChatInput,
18
+ chat_state_manager: ChatStateManager,
19
+ ):
20
+ super().__init__()
21
+
22
+ self._phases = phases
23
+ self._ai_chat_generator = ai_chat_generator
24
+ self._user_chat_input = user_chat_input
25
+ self._chat_state_manager = chat_state_manager
26
+
27
+ async def run(self) -> None:
28
+ await self._phases.set_phase(ChatPhase.STARTING)
29
+ await self._phases.set_phase(ChatPhase.STARTED)
30
+
31
+ while True:
32
+ next_user_chat = await self._user_chat_input.get_next_user_messages()
33
+ if not next_user_chat:
34
+ break
35
+
36
+ prev_user_chat = (await self._chat_state_manager.get_state()).chat
37
+
38
+ next_ai_chat = await self._ai_chat_generator.get_next_ai_messages([*prev_user_chat, *next_user_chat])
39
+
40
+ await self._chat_state_manager.extend_chat([*next_user_chat, *next_ai_chat])
41
+
42
+ await self._phases.set_phase(ChatPhase.STOPPING)
43
+ await self._phases.set_phase(ChatPhase.STOPPED)
@@ -1,96 +1,70 @@
1
- import typing as ta
2
-
3
- from omlish import dataclasses as dc
4
1
  from omlish import inject as inj
5
2
  from omlish import lang
6
3
 
7
- from .base import ChatOption
8
- from .base import ChatOptions
9
- from .base import ChatSession
10
- from .printing import ChatSessionPrinter
11
- from .printing import MarkdownStringChatSessionPrinter
12
- from .printing import SimpleStringChatSessionPrinter
13
- from .state import ChatStateManager
14
- from .state import StateStorageChatStateManager
15
- from .tools import AskingToolExecutionConfirmation
16
- from .tools import NopToolExecutionConfirmation
17
- from .tools import ToolExecutionConfirmation
18
- from .tools import ToolUseExecutor
19
- from .tools import ToolUseExecutorImpl
20
-
21
-
22
- ##
23
-
4
+ from .configs import DEFAULT_CHAT_MODEL_BACKEND
5
+ from .configs import ChatConfig
24
6
 
25
- @dc.dataclass(frozen=True, eq=False)
26
- class _InjectedChatOptions:
27
- v: ChatOptions
28
7
 
29
-
30
- def bind_chat_options(*cos: ChatOption) -> inj.Elements:
31
- return inj.bind_set_entry_const(ta.AbstractSet[_InjectedChatOptions], _InjectedChatOptions(ChatOptions(cos)))
8
+ with lang.auto_proxy_import(globals()):
9
+ from . import driver as _driver
10
+ from .backends import inject as _backends
11
+ from .chat.ai import inject as _chat_ai
12
+ from .chat.state import inject as _chat_state
13
+ from .chat.user import inject as _chat_user
14
+ from .phases import inject as _phases
15
+ from .rendering import inject as _rendering
16
+ from .tools import inject as _tools
32
17
 
33
18
 
34
19
  ##
35
20
 
36
21
 
37
- def bind_chat_session(cfg: ChatSession.Config) -> inj.Elements:
22
+ def bind_chat(cfg: ChatConfig) -> inj.Elements:
38
23
  els: list[inj.Elemental] = []
39
24
 
40
25
  #
41
26
 
42
27
  els.extend([
43
- inj.set_binder[_InjectedChatOptions](),
44
- inj.bind(
45
- lang.typed_lambda(ChatOptions, s=ta.AbstractSet[_InjectedChatOptions])(
46
- lambda s: ChatOptions([
47
- co
48
- for ico in s
49
- for co in ico.v
50
- ]),
51
- ),
52
- singleton=True,
28
+ _backends.bind_backends(
29
+ backend=cfg.backend or DEFAULT_CHAT_MODEL_BACKEND,
53
30
  ),
54
- ])
55
31
 
56
- #
32
+ _chat_ai.bind_ai(
33
+ stream=cfg.stream,
34
+ silent=cfg.silent,
35
+ enable_tools=cfg.enable_tools,
36
+ ),
57
37
 
58
- els.extend([
59
- inj.bind(StateStorageChatStateManager, singleton=True),
60
- inj.bind(ChatStateManager, to_key=StateStorageChatStateManager),
61
- ])
38
+ _chat_user.bind_user(
39
+ initial_system_content=cfg.initial_system_content,
40
+ initial_user_content=cfg.initial_user_content,
41
+ interactive=cfg.interactive,
42
+ ),
62
43
 
63
- #
44
+ _chat_state.bind_state(
45
+ state=cfg.state,
46
+ ),
47
+
48
+ _phases.bind_phases(),
64
49
 
65
- if cfg.markdown:
66
- els.extend([
67
- inj.bind(MarkdownStringChatSessionPrinter, singleton=True),
68
- inj.bind(ChatSessionPrinter, to_key=MarkdownStringChatSessionPrinter),
69
- ])
70
- else:
71
- els.extend([
72
- inj.bind(SimpleStringChatSessionPrinter, singleton=True),
73
- inj.bind(ChatSessionPrinter, to_key=SimpleStringChatSessionPrinter),
74
- ])
50
+ _rendering.bind_rendering(
51
+ markdown=cfg.markdown,
52
+ ),
53
+ ])
75
54
 
76
55
  #
77
56
 
78
- if cfg.dangerous_no_tool_confirmation:
79
- els.extend([
80
- inj.bind(NopToolExecutionConfirmation, singleton=True),
81
- inj.bind(ToolExecutionConfirmation, to_key=NopToolExecutionConfirmation),
82
- ])
83
- else:
84
- els.extend([
85
- inj.bind(AskingToolExecutionConfirmation, singleton=True),
86
- inj.bind(ToolExecutionConfirmation, to_key=AskingToolExecutionConfirmation),
87
- ])
57
+ if cfg.enable_tools:
58
+ els.append(_tools.bind_tools(
59
+ silent=cfg.silent,
60
+ dangerous_no_confirmation=cfg.dangerous_no_tool_confirmation,
61
+ enabled_tools=cfg.enabled_tools,
62
+ ))
88
63
 
89
64
  #
90
65
 
91
66
  els.extend([
92
- inj.bind(ToolUseExecutorImpl, singleton=True),
93
- inj.bind(ToolUseExecutor, to_key=ToolUseExecutorImpl),
67
+ inj.bind(_driver.ChatDriver, singleton=True),
94
68
  ])
95
69
 
96
70
  #
File without changes
@@ -0,0 +1,27 @@
1
+ from omlish import inject as inj
2
+ from omlish import lang
3
+
4
+ from .injection import phase_callbacks
5
+
6
+
7
+ with lang.auto_proxy_import(globals()):
8
+ from . import manager as _manager
9
+
10
+
11
+ ##
12
+
13
+
14
+ def bind_phases() -> inj.Elements:
15
+ els: list[inj.Elemental] = []
16
+
17
+ #
18
+
19
+ els.append(phase_callbacks().bind_items_provider(singleton=True))
20
+
21
+ #
22
+
23
+ els.append(inj.bind(_manager.ChatPhaseManager, 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 phase_callbacks() -> 'inj.ItemsBinderHelper[_types.ChatPhaseCallback]':
14
+ return inj.items_binder_helper[_types.ChatPhaseCallback](_types.ChatPhaseCallbacks)
@@ -0,0 +1,29 @@
1
+ from omlish import check
2
+ from omlish import collections as col
3
+
4
+ from .types import ChatPhase
5
+ from .types import ChatPhaseCallbacks
6
+
7
+
8
+ ##
9
+
10
+
11
+ class ChatPhaseManager:
12
+ def __init__(self, callbacks: ChatPhaseCallbacks) -> None:
13
+ super().__init__()
14
+
15
+ self._callbacks = callbacks
16
+ self._callbacks_by_phase = col.multi_map_by(lambda cb: cb.phase, callbacks)
17
+
18
+ check.state(not self._callbacks_by_phase.get(ChatPhase.NEW))
19
+
20
+ self._phase = ChatPhase.NEW
21
+
22
+ @property
23
+ def phase(self) -> ChatPhase:
24
+ return self._phase
25
+
26
+ async def set_phase(self, phase: ChatPhase) -> None:
27
+ self._phase = phase
28
+ for cb in self._callbacks_by_phase.get(phase, ()):
29
+ await cb.fn()