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
@@ -1,161 +0,0 @@
1
- import dataclasses as dc
2
- import os
3
-
4
- from omlish import check
5
- from omlish import lang
6
-
7
- from .... import minichain as mc
8
- from .base import DEFAULT_CHAT_MODEL_BACKEND
9
- from .base import ChatOptions
10
- from .base import ChatSession
11
- from .printing import ChatSessionPrinter
12
- from .printing import MarkdownStreamPrinter
13
- from .printing import SimpleStreamPrinter
14
- from .printing import StreamPrinter
15
- from .state import ChatStateManager
16
- from .tools import ToolUseExecutor
17
-
18
-
19
- ##
20
-
21
-
22
- class ToolExecutionRequestDeniedError(Exception):
23
- pass
24
-
25
-
26
- class PromptChatSession(ChatSession['PromptChatSession.Config']):
27
- @dc.dataclass(frozen=True)
28
- class Config(ChatSession.Config): # noqa
29
- content: mc.Content
30
-
31
- _: dc.KW_ONLY
32
-
33
- new: bool = False
34
-
35
- backend: str | None = None
36
- model_name: str | None = None
37
-
38
- stream: bool = False
39
-
40
- def __init__(
41
- self,
42
- config: Config,
43
- *,
44
- state_manager: ChatStateManager,
45
- chat_options: ChatOptions | None = None,
46
- printer: ChatSessionPrinter,
47
- backend_catalog: mc.BackendCatalog,
48
- tool_exec_request_executor: ToolUseExecutor,
49
- ) -> None:
50
- super().__init__(config)
51
-
52
- self._state_manager = state_manager
53
- self._chat_options = chat_options
54
- self._printer = printer
55
- self._backend_catalog = backend_catalog
56
- self._tool_exec_request_executor = tool_exec_request_executor
57
-
58
- async def run(self) -> None:
59
- if self._config.stream:
60
- await self._run_stream()
61
- else:
62
- await self._run_immediate()
63
-
64
- async def _run_stream(self) -> None:
65
- prompt = check.isinstance(self._config.content, str)
66
-
67
- if self._config.new:
68
- state = self._state_manager.clear_state()
69
- else:
70
- state = self._state_manager.get_state()
71
-
72
- new_chat: list[mc.Message] = [
73
- mc.UserMessage(prompt),
74
- ]
75
-
76
- mdl: mc.ChatChoicesStreamService
77
- async with lang.async_maybe_managing(self._backend_catalog.get_backend(
78
- mc.ChatChoicesStreamService,
79
- self._config.backend or DEFAULT_CHAT_MODEL_BACKEND,
80
- *([mc.ModelName(mn)] if (mn := self._config.model_name) is not None else []),
81
- )) as mdl:
82
- async with (await mdl.invoke(mc.ChatChoicesStreamRequest(
83
- [*state.chat, *new_chat],
84
- (self._chat_options or []),
85
- ))).v as st_resp:
86
- lst: list[str] = []
87
-
88
- sp_cls: type[StreamPrinter]
89
- if self._config.markdown:
90
- sp_cls = MarkdownStreamPrinter
91
- else:
92
- sp_cls = SimpleStreamPrinter
93
- with sp_cls() as sp:
94
- async for o in st_resp:
95
- if o:
96
- c = check.isinstance(check.single(check.single(o.choices).deltas), mc.ContentAiChoiceDelta).c # noqa
97
- if c is not None:
98
- s = check.isinstance(c, str)
99
- sp.feed(s)
100
- lst.append(s)
101
-
102
- resp_m = mc.AiMessage(''.join(lst))
103
- new_chat.append(resp_m)
104
-
105
- self._state_manager.extend_chat(new_chat)
106
-
107
- async def _run_immediate(self) -> None:
108
- prompt = check.isinstance(self._config.content, str)
109
-
110
- if self._config.new:
111
- state = self._state_manager.clear_state()
112
- else:
113
- state = self._state_manager.get_state()
114
-
115
- new_chat: list[mc.Message] = [
116
- mc.UserMessage(prompt),
117
- ]
118
-
119
- mdl: mc.ChatChoicesService
120
- async with lang.async_maybe_managing(self._backend_catalog.get_backend(
121
- mc.ChatChoicesService,
122
- self._config.backend or DEFAULT_CHAT_MODEL_BACKEND,
123
- *([mc.ModelName(mn)] if (mn := self._config.model_name) is not None else []),
124
- )) as mdl:
125
- response: mc.ChatChoicesResponse = await mdl.invoke(mc.ChatChoicesRequest(
126
- [*state.chat, *new_chat],
127
- (self._chat_options or []),
128
- ))
129
-
130
- for resp_m in response.v[0].ms:
131
- new_chat.append(resp_m)
132
-
133
- if isinstance(resp_m, mc.AiMessage):
134
- self._printer.print(resp_m)
135
-
136
- elif isinstance(resp_m, mc.ToolUseMessage):
137
- tr: mc.ToolUse = resp_m.tu
138
-
139
- # FIXME: lol
140
- from ....minichain.lib.fs.context import FsContext
141
-
142
- trm = await self._tool_exec_request_executor.execute_tool_use(
143
- tr,
144
- FsContext(root_dir=os.getcwd()),
145
- )
146
-
147
- print(trm.tur.c)
148
- new_chat.append(trm)
149
-
150
- response = await mdl.invoke(mc.ChatChoicesRequest(
151
- [*state.chat, *new_chat],
152
- (self._chat_options or []),
153
- ))
154
-
155
- resp_m = check.isinstance(check.single(response.v[0].ms), mc.AiMessage)
156
- new_chat.append(resp_m)
157
-
158
- else:
159
- raise TypeError(resp_m)
160
-
161
- self._state_manager.extend_chat(new_chat)
@@ -1,110 +0,0 @@
1
- import abc
2
- import dataclasses as dc
3
- import datetime
4
-
5
- from omlish import check
6
- from omlish import lang
7
-
8
- from .... import minichain as mc
9
- from ...state import StateStorage
10
-
11
-
12
- ##
13
-
14
-
15
- @dc.dataclass(frozen=True)
16
- class ChatState:
17
- name: str | None = None
18
-
19
- created_at: datetime.datetime = dc.field(default_factory=lang.utcnow)
20
- updated_at: datetime.datetime = dc.field(default_factory=lang.utcnow)
21
-
22
- chat: mc.Chat = ()
23
-
24
-
25
- ##
26
-
27
-
28
- class ChatStateManager(lang.Abstract):
29
- @abc.abstractmethod
30
- def get_state(self) -> ChatState:
31
- raise NotImplementedError
32
-
33
- @abc.abstractmethod
34
- def clear_state(self) -> ChatState:
35
- raise NotImplementedError
36
-
37
- @abc.abstractmethod
38
- def extend_chat(self, chat_additions: mc.Chat) -> ChatState:
39
- raise NotImplementedError
40
-
41
-
42
- ##
43
-
44
-
45
- class InMemoryChatStateManager(ChatStateManager):
46
- def __init__(self, initial_state: ChatState | None = None) -> None:
47
- super().__init__()
48
-
49
- if initial_state is None:
50
- initial_state = ChatState()
51
- self._state = initial_state
52
-
53
- def get_state(self) -> ChatState:
54
- return self._state
55
-
56
- def clear_state(self) -> ChatState:
57
- self._state = ChatState()
58
- return self._state
59
-
60
- def extend_chat(self, chat_additions: mc.Chat) -> ChatState:
61
- self._state = dc.replace(
62
- self._state,
63
- chat=[*self._state.chat, *chat_additions],
64
- updated_at=lang.utcnow(),
65
- )
66
- return self._state
67
-
68
-
69
- ##
70
-
71
-
72
- class StateStorageChatStateManager(ChatStateManager):
73
- def __init__(
74
- self,
75
- *,
76
- storage: StateStorage,
77
- key: str = 'chat',
78
- ) -> None:
79
- super().__init__()
80
-
81
- self._storage = storage
82
- self._key = check.non_empty_str(key)
83
-
84
- self._state: ChatState | None = None
85
-
86
- def get_state(self) -> ChatState:
87
- if self._state is not None:
88
- return self._state
89
- state: ChatState | None = self._storage.load_state(self._key, ChatState)
90
- if state is None:
91
- state = ChatState()
92
- self._state = state
93
- return state
94
-
95
- def clear_state(self) -> ChatState:
96
- state = ChatState()
97
- self._storage.save_state(self._key, state, ChatState)
98
- self._state = state
99
- return state
100
-
101
- def extend_chat(self, chat_additions: mc.Chat) -> ChatState:
102
- state = self.get_state()
103
- state = dc.replace(
104
- state,
105
- chat=[*state.chat, *chat_additions],
106
- updated_at=lang.utcnow(),
107
- )
108
- self._storage.save_state(self._key, state, ChatState)
109
- self._state = state
110
- return state
@@ -1,97 +0,0 @@
1
- import abc
2
- import typing as ta
3
-
4
- from omlish import check
5
- from omlish import lang
6
- from omlish.formats import json
7
- from omlish.term.confirm import confirm_action
8
-
9
- from .... import minichain as mc
10
-
11
-
12
- ##
13
-
14
-
15
- class ToolExecutionRequestDeniedError(Exception):
16
- pass
17
-
18
-
19
- class ToolExecutionConfirmation(lang.Abstract):
20
- @abc.abstractmethod
21
- def confirm_tool_execution_or_raise(
22
- self,
23
- tr: mc.ToolUse,
24
- tce: mc.ToolCatalogEntry,
25
- ) -> ta.Awaitable[None]:
26
- raise NotImplementedError
27
-
28
-
29
- class NopToolExecutionConfirmation(ToolExecutionConfirmation):
30
- async def confirm_tool_execution_or_raise(
31
- self,
32
- tr: mc.ToolUse,
33
- tce: mc.ToolCatalogEntry,
34
- ) -> None:
35
- pass
36
-
37
-
38
- class AskingToolExecutionConfirmation(ToolExecutionConfirmation):
39
- async def confirm_tool_execution_or_raise(
40
- self,
41
- tr: mc.ToolUse,
42
- tce: mc.ToolCatalogEntry,
43
- ) -> None:
44
- tr_dct = dict(
45
- id=tr.id,
46
- name=tce.spec.name,
47
- args=tr.args,
48
- # spec=msh.marshal(tce.spec),
49
- )
50
- cr = confirm_action(f'Execute requested tool?\n\n{json.dumps_pretty(tr_dct)}') # FIXME: async lol
51
-
52
- if not cr:
53
- raise ToolExecutionRequestDeniedError
54
-
55
-
56
- ##
57
-
58
-
59
- class ToolUseExecutor(lang.Abstract):
60
- @abc.abstractmethod
61
- def execute_tool_use(
62
- self,
63
- tr: mc.ToolUse,
64
- *ctx_items: ta.Any,
65
- ) -> ta.Awaitable[mc.ToolUseResultMessage]:
66
- raise NotImplementedError
67
-
68
-
69
- class ToolUseExecutorImpl(ToolUseExecutor):
70
- def __init__(
71
- self,
72
- *,
73
- catalog: mc.ToolCatalog,
74
- confirmation: ToolExecutionConfirmation,
75
- ) -> None:
76
- super().__init__()
77
-
78
- self._catalog = catalog
79
- self._confirmation = confirmation
80
-
81
- async def execute_tool_use(
82
- self,
83
- tr: mc.ToolUse,
84
- *ctx_items: ta.Any,
85
- ) -> mc.ToolUseResultMessage:
86
- tce = self._catalog.by_name[check.non_empty_str(tr.name)]
87
-
88
- await self._confirmation.confirm_tool_execution_or_raise(tr, tce)
89
-
90
- return await mc.execute_tool_use(
91
- mc.ToolContext(
92
- tr,
93
- *ctx_items,
94
- ),
95
- tce.executor(),
96
- tr,
97
- )
@@ -1,14 +0,0 @@
1
- from omlish import dataclasses as dc
2
-
3
-
4
- ##
5
-
6
-
7
- @dc.dataclass(frozen=True, kw_only=True)
8
- class ToolsConfig:
9
- enable_fs_tools: bool = False
10
- enable_todo_tools: bool = False
11
-
12
- enable_unsafe_tools_do_not_use_lol: bool = False
13
-
14
- enable_test_weather_tool: bool = False
@@ -1,75 +0,0 @@
1
- import dataclasses as dc
2
- import typing as ta
3
-
4
- from omlish import inject as inj
5
- from omlish import lang
6
-
7
- from ... import minichain as mc
8
- from ..sessions.chat.inject import bind_chat_options
9
- from .config import ToolsConfig
10
- from .weather import WEATHER_TOOL
11
-
12
-
13
- ##
14
-
15
-
16
- @dc.dataclass(frozen=True, eq=False)
17
- class _InjectedTool:
18
- tce: mc.ToolCatalogEntry
19
-
20
-
21
- def bind_tool(tce: mc.ToolCatalogEntry) -> inj.Element | inj.Elements:
22
- return inj.as_elements(
23
- inj.bind_set_entry_const(ta.AbstractSet[_InjectedTool], _InjectedTool(tce)),
24
-
25
- bind_chat_options(mc.Tool(tce.spec)),
26
- )
27
-
28
-
29
- ##
30
-
31
-
32
- def bind_tools(tools_config: ToolsConfig) -> inj.Elements:
33
- els: list[inj.Elemental] = [
34
- inj.bind(tools_config),
35
-
36
- inj.bind(mc.ToolCatalog, singleton=True),
37
-
38
- inj.set_binder[_InjectedTool](),
39
- inj.bind(
40
- lang.typed_lambda(mc.ToolCatalogEntries, s=ta.AbstractSet[_InjectedTool])(
41
- lambda s: [it.tce for it in s],
42
- ),
43
- singleton=True,
44
- ),
45
- ]
46
-
47
- #
48
-
49
- if tools_config.enable_fs_tools:
50
- from ...minichain.lib.fs.tools.ls import ls_tool
51
- els.append(bind_tool(ls_tool()))
52
-
53
- from ...minichain.lib.fs.tools.read import read_tool
54
- els.append(bind_tool(read_tool()))
55
-
56
- if tools_config.enable_todo_tools:
57
- from ...minichain.lib.todo.tools.read import todo_read_tool
58
- els.append(bind_tool(todo_read_tool()))
59
-
60
- from ...minichain.lib.todo.tools.write import todo_write_tool
61
- els.append(bind_tool(todo_write_tool()))
62
-
63
- if tools_config.enable_unsafe_tools_do_not_use_lol:
64
- from ...minichain.lib.bash import bash_tool
65
- els.append(bind_tool(bash_tool()))
66
-
67
- from ...minichain.lib.fs.tools.edit import edit_tool
68
- els.append(bind_tool(edit_tool()))
69
-
70
- if tools_config.enable_test_weather_tool:
71
- els.append(bind_tool(WEATHER_TOOL))
72
-
73
- #
74
-
75
- return inj.as_elements(*els)