ommlds 0.0.0.dev463__py3-none-any.whl → 0.0.0.dev465__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.
- ommlds/.omlish-manifests.json +2 -2
- ommlds/cli/inject.py +14 -32
- ommlds/cli/main.py +34 -59
- ommlds/cli/sessions/{chat2 → chat}/backends/catalog.py +5 -5
- ommlds/cli/sessions/chat/backends/inject.py +37 -0
- ommlds/cli/sessions/chat/backends/injection.py +16 -0
- ommlds/cli/sessions/{chat2 → chat}/backends/types.py +3 -3
- ommlds/cli/sessions/chat/chat/ai/inject.py +78 -0
- ommlds/cli/sessions/chat/chat/ai/injection.py +14 -0
- ommlds/cli/sessions/{chat2 → chat}/chat/ai/rendering.py +13 -10
- ommlds/cli/sessions/chat/chat/ai/services.py +81 -0
- ommlds/cli/sessions/chat/chat/ai/tools.py +44 -0
- ommlds/cli/sessions/{chat2 → chat}/chat/ai/types.py +5 -5
- ommlds/cli/sessions/chat/chat/state/inject.py +40 -0
- ommlds/cli/sessions/{chat2 → chat}/chat/state/inmemory.py +1 -1
- ommlds/cli/sessions/{chat2 → chat}/chat/state/storage.py +2 -2
- ommlds/cli/sessions/{chat2 → chat}/chat/state/types.py +1 -1
- ommlds/cli/sessions/chat/chat/user/inject.py +61 -0
- ommlds/cli/sessions/{chat2 → chat}/chat/user/interactive.py +1 -1
- ommlds/cli/sessions/{chat2 → chat}/chat/user/oneshot.py +1 -1
- ommlds/cli/sessions/{chat2 → chat}/chat/user/types.py +1 -1
- ommlds/cli/sessions/{chat2 → chat}/configs.py +4 -1
- ommlds/cli/sessions/{chat2 → chat}/content/messages.py +6 -2
- ommlds/cli/sessions/{chat2 → chat}/content/strings.py +2 -2
- ommlds/cli/sessions/{chat2 → chat}/driver.py +2 -2
- ommlds/cli/sessions/chat/inject.py +47 -63
- ommlds/cli/sessions/chat/phases/inject.py +27 -0
- ommlds/cli/sessions/chat/phases/injection.py +14 -0
- ommlds/cli/sessions/{chat2/phases.py → chat/phases/manager.py} +2 -28
- ommlds/cli/sessions/chat/phases/types.py +29 -0
- ommlds/cli/sessions/chat/rendering/inject.py +32 -0
- ommlds/cli/sessions/{chat2 → chat}/rendering/markdown.py +2 -2
- ommlds/cli/sessions/{chat2 → chat}/rendering/raw.py +6 -6
- ommlds/cli/sessions/{chat2 → chat}/rendering/types.py +1 -1
- ommlds/cli/sessions/{chat2 → chat}/session.py +1 -1
- ommlds/cli/sessions/{chat2 → chat}/tools/confirmation.py +4 -4
- ommlds/cli/sessions/{chat2 → chat}/tools/execution.py +18 -5
- ommlds/cli/sessions/chat/tools/inject.py +145 -0
- ommlds/cli/sessions/chat/tools/injection.py +29 -0
- ommlds/cli/sessions/chat/tools/rendering.py +58 -0
- ommlds/cli/{tools → sessions/chat/tools}/weather.py +1 -1
- ommlds/cli/sessions/completion/configs.py +21 -0
- ommlds/cli/sessions/completion/inject.py +28 -0
- ommlds/cli/sessions/completion/{completion.py → session.py} +4 -9
- ommlds/cli/sessions/embedding/configs.py +21 -0
- ommlds/cli/sessions/embedding/inject.py +28 -0
- ommlds/cli/sessions/embedding/{embedding.py → session.py} +4 -9
- ommlds/cli/sessions/inject.py +27 -15
- ommlds/cli/state/inject.py +28 -0
- ommlds/minichain/backends/impls/anthropic/chat.py +4 -61
- ommlds/minichain/backends/impls/anthropic/protocol.py +109 -0
- ommlds/minichain/backends/impls/anthropic/stream.py +17 -17
- {ommlds-0.0.0.dev463.dist-info → ommlds-0.0.0.dev465.dist-info}/METADATA +3 -3
- {ommlds-0.0.0.dev463.dist-info → ommlds-0.0.0.dev465.dist-info}/RECORD +69 -60
- ommlds/cli/sessions/chat/base.py +0 -42
- ommlds/cli/sessions/chat/code.py +0 -125
- ommlds/cli/sessions/chat/interactive.py +0 -70
- ommlds/cli/sessions/chat/printing.py +0 -126
- ommlds/cli/sessions/chat/prompt.py +0 -161
- ommlds/cli/sessions/chat/state.py +0 -110
- ommlds/cli/sessions/chat/tools.py +0 -97
- ommlds/cli/sessions/chat2/_inject.py +0 -105
- ommlds/cli/sessions/chat2/chat/ai/services.py +0 -70
- ommlds/cli/sessions/chat2/inject.py +0 -143
- ommlds/cli/tools/config.py +0 -14
- ommlds/cli/tools/inject.py +0 -75
- /ommlds/cli/sessions/{chat2 → chat/backends}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2/backends → chat/chat}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2/chat → chat/chat/ai}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2/chat/ai → chat/chat/state}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2/chat/state → chat/chat/user}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2/chat/user → chat/content}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2/content → chat/phases}/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2 → chat}/rendering/__init__.py +0 -0
- /ommlds/cli/sessions/{chat2 → chat}/tools/__init__.py +0 -0
- /ommlds/cli/{tools → state}/__init__.py +0 -0
- /ommlds/cli/{state.py → state/storage.py} +0 -0
- {ommlds-0.0.0.dev463.dist-info → ommlds-0.0.0.dev465.dist-info}/WHEEL +0 -0
- {ommlds-0.0.0.dev463.dist-info → ommlds-0.0.0.dev465.dist-info}/entry_points.txt +0 -0
- {ommlds-0.0.0.dev463.dist-info → ommlds-0.0.0.dev465.dist-info}/licenses/LICENSE +0 -0
- {ommlds-0.0.0.dev463.dist-info → ommlds-0.0.0.dev465.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from omlish import check
|
|
5
|
+
from omlish import inject as inj
|
|
6
|
+
from omlish import lang
|
|
7
|
+
|
|
8
|
+
from ..... import minichain as mc
|
|
9
|
+
from .injection import bind_tool_context_provider_to_key
|
|
10
|
+
from .injection import tool_catalog_entries
|
|
11
|
+
from .injection import tool_context_providers
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
with lang.auto_proxy_import(globals()):
|
|
15
|
+
from . import confirmation as _confirmation
|
|
16
|
+
from . import execution as _execution
|
|
17
|
+
from . import rendering as _rendering
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
_TOOL_BINDERS: dict[str, ta.Callable[[], inj.Elements]] = {}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _tool_binder(name: str) -> ta.Callable[[ta.Callable[[], inj.Elements]], ta.Callable[[], inj.Elements]]:
|
|
27
|
+
def inner(fn):
|
|
28
|
+
check.not_in(name, _TOOL_BINDERS)
|
|
29
|
+
_TOOL_BINDERS[name] = fn
|
|
30
|
+
return fn
|
|
31
|
+
return inner
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
#
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@_tool_binder('weather')
|
|
38
|
+
def _bind_weather_tool() -> inj.Elements:
|
|
39
|
+
from .weather import WEATHER_TOOL
|
|
40
|
+
|
|
41
|
+
return inj.as_elements(
|
|
42
|
+
tool_catalog_entries().bind_item_consts(WEATHER_TOOL),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@_tool_binder('todo')
|
|
47
|
+
def _bind_todo_tools() -> inj.Elements:
|
|
48
|
+
from .....minichain.lib.todo.context import TodoContext
|
|
49
|
+
from .....minichain.lib.todo.tools.read import todo_read_tool
|
|
50
|
+
from .....minichain.lib.todo.tools.write import todo_write_tool
|
|
51
|
+
|
|
52
|
+
return inj.as_elements(
|
|
53
|
+
tool_catalog_entries().bind_item_consts(
|
|
54
|
+
todo_read_tool(),
|
|
55
|
+
todo_write_tool(),
|
|
56
|
+
),
|
|
57
|
+
|
|
58
|
+
inj.bind(TodoContext()),
|
|
59
|
+
bind_tool_context_provider_to_key(TodoContext),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@_tool_binder('fs')
|
|
64
|
+
def _bind_fs_tools() -> inj.Elements:
|
|
65
|
+
from .....minichain.lib.fs.context import FsContext
|
|
66
|
+
from .....minichain.lib.fs.tools.ls import ls_tool
|
|
67
|
+
from .....minichain.lib.fs.tools.read import read_tool
|
|
68
|
+
|
|
69
|
+
return inj.as_elements(
|
|
70
|
+
tool_catalog_entries().bind_item_consts(
|
|
71
|
+
ls_tool(),
|
|
72
|
+
read_tool(),
|
|
73
|
+
),
|
|
74
|
+
|
|
75
|
+
inj.bind(FsContext(
|
|
76
|
+
root_dir=os.getcwd(),
|
|
77
|
+
)),
|
|
78
|
+
bind_tool_context_provider_to_key(FsContext),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# if tools_config.enable_unsafe_tools_do_not_use_lol:
|
|
83
|
+
# from ...minichain.lib.bash import bash_tool
|
|
84
|
+
# els.append(bind_tool(bash_tool()))
|
|
85
|
+
#
|
|
86
|
+
# from ...minichain.lib.fs.tools.edit import edit_tool
|
|
87
|
+
# els.append(bind_tool(edit_tool()))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
##
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def bind_tools(
|
|
94
|
+
*,
|
|
95
|
+
silent: bool = False,
|
|
96
|
+
dangerous_no_confirmation: bool = False,
|
|
97
|
+
enabled_tools: ta.Iterable[str] | None = None,
|
|
98
|
+
) -> inj.Elements:
|
|
99
|
+
els: list[inj.Elemental] = []
|
|
100
|
+
|
|
101
|
+
#
|
|
102
|
+
|
|
103
|
+
els.append(inj.bind(mc.ToolCatalog, singleton=True))
|
|
104
|
+
|
|
105
|
+
#
|
|
106
|
+
|
|
107
|
+
els.append(tool_catalog_entries().bind_items_provider(singleton=True))
|
|
108
|
+
|
|
109
|
+
for etn in check.not_isinstance(enabled_tools or [], str):
|
|
110
|
+
els.append(_TOOL_BINDERS[etn]())
|
|
111
|
+
|
|
112
|
+
#
|
|
113
|
+
|
|
114
|
+
exec_stack = inj.wrapper_binder_helper(_execution.ToolUseExecutor)
|
|
115
|
+
|
|
116
|
+
els.append(exec_stack.push_bind(to_ctor=_execution.ToolUseExecutorImpl, singleton=True))
|
|
117
|
+
|
|
118
|
+
if not silent:
|
|
119
|
+
els.append(exec_stack.push_bind(to_ctor=_rendering.ResultRenderingToolUseExecutor, singleton=True))
|
|
120
|
+
|
|
121
|
+
if dangerous_no_confirmation:
|
|
122
|
+
els.append(exec_stack.push_bind(to_ctor=_rendering.ArgsRenderingToolUseExecutor, singleton=True))
|
|
123
|
+
|
|
124
|
+
els.extend([
|
|
125
|
+
inj.bind(_execution.ToolUseExecutor, to_key=exec_stack.top),
|
|
126
|
+
])
|
|
127
|
+
|
|
128
|
+
#
|
|
129
|
+
|
|
130
|
+
if not dangerous_no_confirmation:
|
|
131
|
+
els.append(inj.bind(_confirmation.ToolExecutionConfirmation, to_ctor=_confirmation.InteractiveToolExecutionConfirmation, singleton=True)) # noqa
|
|
132
|
+
|
|
133
|
+
#
|
|
134
|
+
|
|
135
|
+
els.extend([
|
|
136
|
+
tool_context_providers().bind_items_provider(singleton=True),
|
|
137
|
+
|
|
138
|
+
inj.bind(_execution.ToolContextProvider, to_fn=lang.typed_lambda(tcps=_execution.ToolContextProviders)(
|
|
139
|
+
lambda tcps: _execution.ToolContextProvider(lambda: [tc for tcp in tcps for tc in tcp()]),
|
|
140
|
+
), singleton=True),
|
|
141
|
+
])
|
|
142
|
+
|
|
143
|
+
#
|
|
144
|
+
|
|
145
|
+
return inj.as_elements(*els)
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
|
|
8
|
+
|
|
9
|
+
with lang.auto_proxy_import(globals()):
|
|
10
|
+
from . import execution as _execution
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@lang.cached_function
|
|
16
|
+
def tool_catalog_entries() -> 'inj.ItemsBinderHelper[mc.ToolCatalogEntry]':
|
|
17
|
+
return inj.items_binder_helper[mc.ToolCatalogEntry](mc.ToolCatalogEntries)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@lang.cached_function
|
|
21
|
+
def tool_context_providers() -> 'inj.ItemsBinderHelper[_execution.ToolContextProvider]':
|
|
22
|
+
return inj.items_binder_helper[_execution.ToolContextProvider](_execution.ToolContextProviders)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def bind_tool_context_provider_to_key(key: ta.Any) -> inj.Elements:
|
|
26
|
+
return tool_context_providers().bind_item(to_fn=inj.KwargsTarget.of(
|
|
27
|
+
lambda v: _execution.ToolContextProvider(lambda: [v]),
|
|
28
|
+
v=key,
|
|
29
|
+
), singleton=True)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from ..... import minichain as mc
|
|
4
|
+
from ..rendering.types import ContentRendering
|
|
5
|
+
from .execution import ToolUseExecutor
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ArgsRenderingToolUseExecutor(ToolUseExecutor):
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
*,
|
|
15
|
+
wrapped: ToolUseExecutor,
|
|
16
|
+
renderer: ContentRendering,
|
|
17
|
+
) -> None:
|
|
18
|
+
super().__init__()
|
|
19
|
+
|
|
20
|
+
self._wrapped = wrapped
|
|
21
|
+
self._renderer = renderer
|
|
22
|
+
|
|
23
|
+
async def execute_tool_use(
|
|
24
|
+
self,
|
|
25
|
+
use: 'mc.ToolUse',
|
|
26
|
+
*ctx_items: ta.Any,
|
|
27
|
+
) -> 'mc.ToolUseResultMessage':
|
|
28
|
+
await self._renderer.render_content(mc.JsonContent(dict(
|
|
29
|
+
id=use.id,
|
|
30
|
+
name=use.name,
|
|
31
|
+
args=use.args,
|
|
32
|
+
)))
|
|
33
|
+
|
|
34
|
+
return await self._wrapped.execute_tool_use(use, *ctx_items)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ResultRenderingToolUseExecutor(ToolUseExecutor):
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
*,
|
|
41
|
+
wrapped: ToolUseExecutor,
|
|
42
|
+
renderer: ContentRendering,
|
|
43
|
+
) -> None:
|
|
44
|
+
super().__init__()
|
|
45
|
+
|
|
46
|
+
self._wrapped = wrapped
|
|
47
|
+
self._renderer = renderer
|
|
48
|
+
|
|
49
|
+
async def execute_tool_use(
|
|
50
|
+
self,
|
|
51
|
+
use: 'mc.ToolUse',
|
|
52
|
+
*ctx_items: ta.Any,
|
|
53
|
+
) -> 'mc.ToolUseResultMessage':
|
|
54
|
+
out = await self._wrapped.execute_tool_use(use, *ctx_items)
|
|
55
|
+
|
|
56
|
+
await self._renderer.render_content(out.tur.c)
|
|
57
|
+
|
|
58
|
+
return out
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import dataclasses as dc
|
|
2
|
+
|
|
3
|
+
from .... import minichain as mc
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
DEFAULT_COMPLETION_MODEL_BACKEND = 'openai'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dc.dataclass(frozen=True)
|
|
16
|
+
class CompletionConfig:
|
|
17
|
+
content: 'mc.Content'
|
|
18
|
+
|
|
19
|
+
_: dc.KW_ONLY
|
|
20
|
+
|
|
21
|
+
backend: str | None = None
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from omlish import dataclasses as dc
|
|
2
|
+
from omlish import inject as inj
|
|
3
|
+
from omlish import lang
|
|
4
|
+
|
|
5
|
+
from ..base import Session
|
|
6
|
+
from .configs import CompletionConfig
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
with lang.auto_proxy_import(globals()):
|
|
10
|
+
from . import session as _session
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def bind_completion(cfg: CompletionConfig) -> inj.Elements:
|
|
17
|
+
els: list[inj.Elemental] = []
|
|
18
|
+
|
|
19
|
+
#
|
|
20
|
+
|
|
21
|
+
els.extend([
|
|
22
|
+
inj.bind(_session.CompletionSession.Config(**dc.asdict(cfg))),
|
|
23
|
+
inj.bind(Session, to_ctor=_session.CompletionSession, singleton=True),
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
|
|
28
|
+
return inj.as_elements(*els)
|
|
@@ -5,22 +5,17 @@ from omlish import lang
|
|
|
5
5
|
|
|
6
6
|
from .... import minichain as mc
|
|
7
7
|
from ..base import Session
|
|
8
|
+
from .configs import DEFAULT_COMPLETION_MODEL_BACKEND
|
|
9
|
+
from .configs import CompletionConfig
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
##
|
|
11
13
|
|
|
12
14
|
|
|
13
|
-
DEFAULT_COMPLETION_MODEL_BACKEND = 'openai'
|
|
14
|
-
|
|
15
|
-
|
|
16
15
|
class CompletionSession(Session['CompletionSession.Config']):
|
|
17
16
|
@dc.dataclass(frozen=True)
|
|
18
|
-
class Config(Session.Config):
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
_: dc.KW_ONLY
|
|
22
|
-
|
|
23
|
-
backend: str | None = None
|
|
17
|
+
class Config(Session.Config, CompletionConfig):
|
|
18
|
+
pass
|
|
24
19
|
|
|
25
20
|
def __init__(
|
|
26
21
|
self,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import dataclasses as dc
|
|
2
|
+
|
|
3
|
+
from .... import minichain as mc
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
DEFAULT_EMBEDDING_MODEL_BACKEND = 'openai'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dc.dataclass(frozen=True)
|
|
16
|
+
class EmbeddingConfig:
|
|
17
|
+
content: 'mc.Content'
|
|
18
|
+
|
|
19
|
+
_: dc.KW_ONLY
|
|
20
|
+
|
|
21
|
+
backend: str | None = None
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from omlish import dataclasses as dc
|
|
2
|
+
from omlish import inject as inj
|
|
3
|
+
from omlish import lang
|
|
4
|
+
|
|
5
|
+
from ..base import Session
|
|
6
|
+
from .configs import EmbeddingConfig
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
with lang.auto_proxy_import(globals()):
|
|
10
|
+
from . import session as _session
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def bind_embedding(cfg: EmbeddingConfig) -> inj.Elements:
|
|
17
|
+
els: list[inj.Elemental] = []
|
|
18
|
+
|
|
19
|
+
#
|
|
20
|
+
|
|
21
|
+
els.extend([
|
|
22
|
+
inj.bind(_session.EmbeddingSession.Config(**dc.asdict(cfg))),
|
|
23
|
+
inj.bind(Session, to_ctor=_session.EmbeddingSession, singleton=True),
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
|
|
28
|
+
return inj.as_elements(*els)
|
|
@@ -5,22 +5,17 @@ from omlish.formats import json
|
|
|
5
5
|
|
|
6
6
|
from .... import minichain as mc
|
|
7
7
|
from ..base import Session
|
|
8
|
+
from .configs import DEFAULT_EMBEDDING_MODEL_BACKEND
|
|
9
|
+
from .configs import EmbeddingConfig
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
##
|
|
11
13
|
|
|
12
14
|
|
|
13
|
-
DEFAULT_EMBEDDING_MODEL_BACKEND = 'openai'
|
|
14
|
-
|
|
15
|
-
|
|
16
15
|
class EmbeddingSession(Session['EmbeddingSession.Config']):
|
|
17
16
|
@dc.dataclass(frozen=True)
|
|
18
|
-
class Config(Session.Config):
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
_: dc.KW_ONLY
|
|
22
|
-
|
|
23
|
-
backend: str | None = None
|
|
17
|
+
class Config(Session.Config, EmbeddingConfig):
|
|
18
|
+
pass
|
|
24
19
|
|
|
25
20
|
def __init__(
|
|
26
21
|
self,
|
ommlds/cli/sessions/inject.py
CHANGED
|
@@ -1,26 +1,38 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
1
3
|
from omlish import inject as inj
|
|
4
|
+
from omlish import lang
|
|
5
|
+
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
from .chat
|
|
5
|
-
from .
|
|
7
|
+
with lang.auto_proxy_import(globals()):
|
|
8
|
+
from .chat import configs as _chat_cfgs
|
|
9
|
+
from .chat import inject as _chat_inj
|
|
10
|
+
from .completion import configs as _completion_cfgs
|
|
11
|
+
from .completion import inject as _completion_inj
|
|
12
|
+
from .embedding import configs as _embedding_cfgs
|
|
13
|
+
from .embedding import inject as _embedding_inj
|
|
6
14
|
|
|
7
15
|
|
|
8
16
|
##
|
|
9
17
|
|
|
10
18
|
|
|
11
|
-
def bind_sessions(
|
|
12
|
-
els: list[inj.Elemental] = [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
def bind_sessions(cfg: ta.Any) -> inj.Elements:
|
|
20
|
+
els: list[inj.Elemental] = []
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
|
|
24
|
+
if isinstance(cfg, _chat_cfgs.ChatConfig):
|
|
25
|
+
els.append(_chat_inj.bind_chat(cfg))
|
|
26
|
+
|
|
27
|
+
elif isinstance(cfg, _completion_cfgs.CompletionConfig):
|
|
28
|
+
els.append(_completion_inj.bind_completion(cfg))
|
|
29
|
+
|
|
30
|
+
elif isinstance(cfg, _embedding_cfgs.EmbeddingConfig):
|
|
31
|
+
els.append(_embedding_inj.bind_embedding(cfg))
|
|
17
32
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
els.append(bind_chat_session(session_cfg))
|
|
33
|
+
else:
|
|
34
|
+
raise TypeError(cfg)
|
|
21
35
|
|
|
22
|
-
|
|
23
|
-
from .chat2.inject import bind_chat
|
|
24
|
-
els.append(bind_chat(session_cfg)) # noqa
|
|
36
|
+
#
|
|
25
37
|
|
|
26
38
|
return inj.as_elements(*els)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
|
|
3
|
+
from omdev.home.paths import get_home_paths
|
|
4
|
+
from omlish import inject as inj
|
|
5
|
+
from omlish import lang
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
with lang.auto_proxy_import(globals()):
|
|
9
|
+
from . import storage as _storage
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _provide_state_storage() -> '_storage.StateStorage':
|
|
16
|
+
state_dir = os.path.join(get_home_paths().state_dir, 'minichain', 'cli')
|
|
17
|
+
if not os.path.exists(state_dir):
|
|
18
|
+
os.makedirs(state_dir, exist_ok=True)
|
|
19
|
+
os.chmod(state_dir, 0o770) # noqa
|
|
20
|
+
|
|
21
|
+
state_file = os.path.join(state_dir, 'state.json')
|
|
22
|
+
return _storage.JsonFileStateStorage(state_file)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def bind_state() -> inj.Elements:
|
|
26
|
+
return inj.as_elements(
|
|
27
|
+
inj.bind(_provide_state_storage, singleton=True),
|
|
28
|
+
)
|
|
@@ -22,15 +22,14 @@ from ....chat.messages import AnyAiMessage
|
|
|
22
22
|
from ....chat.messages import Message
|
|
23
23
|
from ....chat.messages import SystemMessage
|
|
24
24
|
from ....chat.messages import ToolUseMessage
|
|
25
|
-
from ....chat.messages import ToolUseResultMessage
|
|
26
25
|
from ....chat.messages import UserMessage
|
|
27
26
|
from ....chat.tools.types import Tool
|
|
28
|
-
from ....content.prepare import prepare_content_str
|
|
29
27
|
from ....models.configs import ModelName
|
|
30
28
|
from ....standard import ApiKey
|
|
31
|
-
from ....tools.jsonschema import build_tool_spec_params_json_schema
|
|
32
29
|
from ....tools.types import ToolUse
|
|
33
30
|
from .names import MODEL_NAMES
|
|
31
|
+
from .protocol import build_protocol_chat_messages
|
|
32
|
+
from .protocol import build_protocol_tool
|
|
34
33
|
|
|
35
34
|
|
|
36
35
|
##
|
|
@@ -44,13 +43,6 @@ from .names import MODEL_NAMES
|
|
|
44
43
|
class AnthropicChatChoicesService:
|
|
45
44
|
DEFAULT_MODEL_NAME: ta.ClassVar[ModelName] = ModelName(check.not_none(MODEL_NAMES.default))
|
|
46
45
|
|
|
47
|
-
ROLES_MAP: ta.ClassVar[ta.Mapping[type[Message], str]] = {
|
|
48
|
-
SystemMessage: 'system',
|
|
49
|
-
UserMessage: 'user',
|
|
50
|
-
AiMessage: 'assistant',
|
|
51
|
-
ToolUseMessage: 'assistant',
|
|
52
|
-
}
|
|
53
|
-
|
|
54
46
|
def __init__(
|
|
55
47
|
self,
|
|
56
48
|
*configs: ApiKey | ModelName,
|
|
@@ -78,62 +70,13 @@ class AnthropicChatChoicesService:
|
|
|
78
70
|
*,
|
|
79
71
|
max_tokens: int = 4096, # FIXME: ChatOption
|
|
80
72
|
) -> ChatChoicesResponse:
|
|
81
|
-
messages
|
|
82
|
-
system: list[pt.Content] | None = None
|
|
83
|
-
for i, m in enumerate(request.v):
|
|
84
|
-
if isinstance(m, SystemMessage):
|
|
85
|
-
if i != 0 or system is not None:
|
|
86
|
-
raise Exception('Only supports one system message and must be first')
|
|
87
|
-
system = [pt.Text(check.not_none(self._get_msg_content(m)))]
|
|
88
|
-
|
|
89
|
-
elif isinstance(m, ToolUseResultMessage):
|
|
90
|
-
messages.append(pt.Message(
|
|
91
|
-
role='user',
|
|
92
|
-
content=[pt.ToolResult(
|
|
93
|
-
tool_use_id=check.not_none(m.tur.id),
|
|
94
|
-
content=json.dumps_compact(msh.marshal(m.tur.c)) if not isinstance(m.tur.c, str) else m.tur.c,
|
|
95
|
-
)],
|
|
96
|
-
))
|
|
97
|
-
|
|
98
|
-
elif isinstance(m, AiMessage):
|
|
99
|
-
# messages.append(pt.Message(
|
|
100
|
-
# role=self.ROLES_MAP[type(m)], # noqa
|
|
101
|
-
# content=[pt.Text(check.isinstance(self._get_msg_content(m), str))],
|
|
102
|
-
# ))
|
|
103
|
-
messages.append(pt.Message(
|
|
104
|
-
role='assistant',
|
|
105
|
-
content=[
|
|
106
|
-
*([pt.Text(check.isinstance(m.c, str))] if m.c is not None else []),
|
|
107
|
-
],
|
|
108
|
-
))
|
|
109
|
-
|
|
110
|
-
elif isinstance(m, ToolUseMessage):
|
|
111
|
-
messages.append(pt.Message(
|
|
112
|
-
role='assistant',
|
|
113
|
-
content=[
|
|
114
|
-
pt.ToolUse(
|
|
115
|
-
id=check.not_none(m.tu.id),
|
|
116
|
-
name=check.not_none(m.tu.name),
|
|
117
|
-
input=m.tu.args,
|
|
118
|
-
),
|
|
119
|
-
],
|
|
120
|
-
))
|
|
121
|
-
|
|
122
|
-
else:
|
|
123
|
-
messages.append(pt.Message(
|
|
124
|
-
role=self.ROLES_MAP[type(m)], # type: ignore[arg-type]
|
|
125
|
-
content=[pt.Text(check.isinstance(self._get_msg_content(m), str))],
|
|
126
|
-
))
|
|
73
|
+
messages, system = build_protocol_chat_messages(request.v)
|
|
127
74
|
|
|
128
75
|
tools: list[pt.ToolSpec] = []
|
|
129
76
|
with tv.TypedValues(*request.options).consume() as oc:
|
|
130
77
|
t: Tool
|
|
131
78
|
for t in oc.pop(Tool, []):
|
|
132
|
-
tools.append(
|
|
133
|
-
name=check.not_none(t.spec.name),
|
|
134
|
-
description=prepare_content_str(t.spec.desc),
|
|
135
|
-
input_schema=build_tool_spec_params_json_schema(t.spec),
|
|
136
|
-
))
|
|
79
|
+
tools.append(build_protocol_tool(t))
|
|
137
80
|
|
|
138
81
|
a_req = pt.MessagesRequest(
|
|
139
82
|
model=MODEL_NAMES.resolve(self._model_name.v),
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from omlish import check
|
|
4
|
+
from omlish import marshal as msh
|
|
5
|
+
from omlish.formats import json
|
|
6
|
+
|
|
7
|
+
from .....backends.anthropic.protocol import types as pt
|
|
8
|
+
from ....chat.messages import AiMessage
|
|
9
|
+
from ....chat.messages import Message
|
|
10
|
+
from ....chat.messages import SystemMessage
|
|
11
|
+
from ....chat.messages import ToolUseMessage
|
|
12
|
+
from ....chat.messages import ToolUseResultMessage
|
|
13
|
+
from ....chat.messages import UserMessage
|
|
14
|
+
from ....chat.tools.types import Tool
|
|
15
|
+
from ....content.prepare import prepare_content_str
|
|
16
|
+
from ....tools.jsonschema import build_tool_spec_params_json_schema
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_message_content(m: Message) -> str | None:
|
|
23
|
+
if isinstance(m, AiMessage):
|
|
24
|
+
return check.isinstance(m.c, str)
|
|
25
|
+
|
|
26
|
+
elif isinstance(m, (UserMessage, SystemMessage)):
|
|
27
|
+
return check.isinstance(m.c, str)
|
|
28
|
+
|
|
29
|
+
else:
|
|
30
|
+
raise TypeError(m)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class BuiltChatMessages(ta.NamedTuple):
|
|
37
|
+
messages: list[pt.Message]
|
|
38
|
+
system: list[pt.Content] | None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
ROLES_MAP: ta.Mapping[type[Message], str] = {
|
|
42
|
+
SystemMessage: 'system',
|
|
43
|
+
UserMessage: 'user',
|
|
44
|
+
AiMessage: 'assistant',
|
|
45
|
+
ToolUseMessage: 'assistant',
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def build_protocol_chat_messages(msgs: ta.Iterable[Message]) -> BuiltChatMessages:
|
|
50
|
+
messages: list[pt.Message] = []
|
|
51
|
+
system: list[pt.Content] | None = None
|
|
52
|
+
|
|
53
|
+
for i, m in enumerate(msgs):
|
|
54
|
+
if isinstance(m, SystemMessage):
|
|
55
|
+
if i or system is not None:
|
|
56
|
+
raise Exception('Only supports one system message and must be first')
|
|
57
|
+
system = [pt.Text(check.not_none(get_message_content(m)))]
|
|
58
|
+
|
|
59
|
+
elif isinstance(m, ToolUseResultMessage):
|
|
60
|
+
messages.append(pt.Message(
|
|
61
|
+
role='user',
|
|
62
|
+
content=[pt.ToolResult(
|
|
63
|
+
tool_use_id=check.not_none(m.tur.id),
|
|
64
|
+
content=json.dumps_compact(msh.marshal(m.tur.c)) if not isinstance(m.tur.c, str) else m.tur.c,
|
|
65
|
+
)],
|
|
66
|
+
))
|
|
67
|
+
|
|
68
|
+
elif isinstance(m, AiMessage):
|
|
69
|
+
# messages.append(pt.Message(
|
|
70
|
+
# role=ROLES_MAP[type(m)], # noqa
|
|
71
|
+
# content=[pt.Text(check.isinstance(get_message_content(m), str))],
|
|
72
|
+
# ))
|
|
73
|
+
messages.append(pt.Message(
|
|
74
|
+
role='assistant',
|
|
75
|
+
content=[
|
|
76
|
+
*([pt.Text(check.isinstance(m.c, str))] if m.c is not None else []),
|
|
77
|
+
],
|
|
78
|
+
))
|
|
79
|
+
|
|
80
|
+
elif isinstance(m, ToolUseMessage):
|
|
81
|
+
messages.append(pt.Message(
|
|
82
|
+
role='assistant',
|
|
83
|
+
content=[
|
|
84
|
+
pt.ToolUse(
|
|
85
|
+
id=check.not_none(m.tu.id),
|
|
86
|
+
name=check.not_none(m.tu.name),
|
|
87
|
+
input=m.tu.args,
|
|
88
|
+
),
|
|
89
|
+
],
|
|
90
|
+
))
|
|
91
|
+
|
|
92
|
+
else:
|
|
93
|
+
messages.append(pt.Message(
|
|
94
|
+
role=ROLES_MAP[type(m)], # type: ignore[arg-type]
|
|
95
|
+
content=[pt.Text(check.isinstance(get_message_content(m), str))],
|
|
96
|
+
))
|
|
97
|
+
|
|
98
|
+
return BuiltChatMessages(messages, system)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
##
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def build_protocol_tool(t: Tool) -> pt.ToolSpec:
|
|
105
|
+
return pt.ToolSpec(
|
|
106
|
+
name=check.not_none(t.spec.name),
|
|
107
|
+
description=prepare_content_str(t.spec.desc),
|
|
108
|
+
input_schema=build_tool_spec_params_json_schema(t.spec),
|
|
109
|
+
)
|