ommlds 0.0.0.dev515__py3-none-any.whl → 0.0.0.dev517__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/__about__.py +3 -3
- ommlds/backends/mlx/generation.py +2 -2
- ommlds/backends/mlx/tokenization/detokenization/naive.py +4 -2
- ommlds/backends/mlx/tokenization/tokenization.py +1 -1
- ommlds/backends/transformers/streamers.py +7 -2
- ommlds/cli/_dataclasses.py +147 -0
- ommlds/cli/inject.py +5 -1
- ommlds/cli/main.py +18 -343
- ommlds/cli/profiles.py +449 -0
- ommlds/cli/sessions/chat/interfaces/textual/app.py +4 -0
- ommlds/cli/sessions/inject.py +11 -1
- ommlds/cli/sessions/types.py +7 -0
- ommlds/minichain/__init__.py +1 -1
- ommlds/minichain/backends/impls/transformers/tokens.py +4 -2
- ommlds/minichain/resources.py +6 -188
- {ommlds-0.0.0.dev515.dist-info → ommlds-0.0.0.dev517.dist-info}/METADATA +10 -10
- {ommlds-0.0.0.dev515.dist-info → ommlds-0.0.0.dev517.dist-info}/RECORD +21 -19
- {ommlds-0.0.0.dev515.dist-info → ommlds-0.0.0.dev517.dist-info}/WHEEL +0 -0
- {ommlds-0.0.0.dev515.dist-info → ommlds-0.0.0.dev517.dist-info}/entry_points.txt +0 -0
- {ommlds-0.0.0.dev515.dist-info → ommlds-0.0.0.dev517.dist-info}/licenses/LICENSE +0 -0
- {ommlds-0.0.0.dev515.dist-info → ommlds-0.0.0.dev517.dist-info}/top_level.txt +0 -0
ommlds/cli/profiles.py
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import sys
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
from omlish import check
|
|
6
|
+
from omlish import dataclasses as dc
|
|
7
|
+
from omlish import lang
|
|
8
|
+
from omlish.argparse import all as ap
|
|
9
|
+
|
|
10
|
+
from .sessions.chat.configs import ChatConfig
|
|
11
|
+
from .sessions.chat.interfaces.bare.configs import BareInterfaceConfig
|
|
12
|
+
from .sessions.chat.interfaces.configs import InterfaceConfig
|
|
13
|
+
from .sessions.chat.interfaces.textual.configs import TextualInterfaceConfig
|
|
14
|
+
from .sessions.completion.configs import CompletionConfig
|
|
15
|
+
from .sessions.configs import SessionConfig
|
|
16
|
+
from .sessions.embedding.configs import EmbeddingConfig
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
SessionConfigT = ta.TypeVar('SessionConfigT', bound=SessionConfig)
|
|
20
|
+
SessionConfigU = ta.TypeVar('SessionConfigU', bound=SessionConfig)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Profile(lang.Abstract, ta.Generic[SessionConfigT]):
|
|
27
|
+
@abc.abstractmethod
|
|
28
|
+
def configure(self, argv: ta.Sequence[str]) -> SessionConfigT:
|
|
29
|
+
raise NotImplementedError
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ProfileAspect(lang.Abstract, ta.Generic[SessionConfigT]):
|
|
36
|
+
@property
|
|
37
|
+
def name(self) -> str:
|
|
38
|
+
return lang.camel_to_snake(type(self).__name__).lower()
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def default_parser_arg_group(self) -> str | None:
|
|
42
|
+
return self.name
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def parser_args(self) -> ta.Sequence[ap.Arg]:
|
|
46
|
+
return []
|
|
47
|
+
|
|
48
|
+
@ta.final
|
|
49
|
+
@dc.dataclass(frozen=True)
|
|
50
|
+
class ConfigureContext(ta.Generic[SessionConfigU]):
|
|
51
|
+
profile: 'Profile[SessionConfigU]'
|
|
52
|
+
args: ap.Namespace
|
|
53
|
+
|
|
54
|
+
@abc.abstractmethod
|
|
55
|
+
def configure(self, ctx: ConfigureContext[SessionConfigT], cfg: SessionConfigT) -> SessionConfigT:
|
|
56
|
+
raise NotImplementedError
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class AspectProfile(Profile[SessionConfigT], lang.Abstract):
|
|
60
|
+
@abc.abstractmethod
|
|
61
|
+
def _build_aspects(self) -> ta.Sequence[ProfileAspect[SessionConfigT]]:
|
|
62
|
+
return []
|
|
63
|
+
|
|
64
|
+
__aspects: ta.Sequence[ProfileAspect[SessionConfigT]]
|
|
65
|
+
|
|
66
|
+
@ta.final
|
|
67
|
+
@property
|
|
68
|
+
def aspects(self) -> ta.Sequence[ProfileAspect[SessionConfigT]]:
|
|
69
|
+
try:
|
|
70
|
+
return self.__aspects
|
|
71
|
+
except AttributeError:
|
|
72
|
+
pass
|
|
73
|
+
self.__aspects = aspects = tuple(self._build_aspects())
|
|
74
|
+
return aspects
|
|
75
|
+
|
|
76
|
+
#
|
|
77
|
+
|
|
78
|
+
@abc.abstractmethod
|
|
79
|
+
def initial_config(self) -> SessionConfigT:
|
|
80
|
+
raise NotImplementedError
|
|
81
|
+
|
|
82
|
+
#
|
|
83
|
+
|
|
84
|
+
def configure(self, argv: ta.Sequence[str]) -> SessionConfigT:
|
|
85
|
+
parser = ap.ArgumentParser()
|
|
86
|
+
|
|
87
|
+
pa_grps: dict[str, ta.Any] = {}
|
|
88
|
+
for a in self.aspects:
|
|
89
|
+
for pa in a.parser_args:
|
|
90
|
+
if (pa_gn := lang.opt_coalesce(pa.group, a.default_parser_arg_group)) is not None:
|
|
91
|
+
check.non_empty_str(pa_gn)
|
|
92
|
+
try:
|
|
93
|
+
pa_grp = pa_grps[pa_gn]
|
|
94
|
+
except KeyError:
|
|
95
|
+
pa_grps[pa_gn] = pa_grp = parser.add_argument_group(pa_gn)
|
|
96
|
+
pa_grp.add_argument(*pa.args, **pa.kwargs)
|
|
97
|
+
else:
|
|
98
|
+
parser.add_argument(*pa.args, **pa.kwargs)
|
|
99
|
+
|
|
100
|
+
args = parser.parse_args(argv)
|
|
101
|
+
|
|
102
|
+
cfg_ctx = ProfileAspect.ConfigureContext(
|
|
103
|
+
self,
|
|
104
|
+
args,
|
|
105
|
+
)
|
|
106
|
+
cfg = self.initial_config()
|
|
107
|
+
for a in self.aspects:
|
|
108
|
+
cfg = a.configure(cfg_ctx, cfg)
|
|
109
|
+
|
|
110
|
+
return cfg
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
##
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class ChatProfile(AspectProfile[ChatConfig]):
|
|
117
|
+
class Backend(ProfileAspect[ChatConfig]):
|
|
118
|
+
parser_args: ta.ClassVar[ta.Sequence[ap.Arg]] = [
|
|
119
|
+
ap.arg('-b', '--backend'),
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
def configure(self, ctx: ProfileAspect.ConfigureContext[ChatConfig], cfg: ChatConfig) -> ChatConfig:
|
|
123
|
+
return dc.replace(
|
|
124
|
+
cfg,
|
|
125
|
+
driver=dc.replace(
|
|
126
|
+
cfg.driver,
|
|
127
|
+
backend=dc.replace(
|
|
128
|
+
cfg.driver.backend,
|
|
129
|
+
backend=ctx.args.backend,
|
|
130
|
+
),
|
|
131
|
+
),
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
#
|
|
135
|
+
|
|
136
|
+
class Interface(ProfileAspect[ChatConfig]):
|
|
137
|
+
parser_args: ta.ClassVar[ta.Sequence[ap.Arg]] = [
|
|
138
|
+
ap.arg('-i', '--interactive', action='store_true'),
|
|
139
|
+
ap.arg('-T', '--textual', action='store_true'),
|
|
140
|
+
ap.arg('-e', '--editor', action='store_true'),
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
def configure(self, ctx: ProfileAspect.ConfigureContext[ChatConfig], cfg: ChatConfig) -> ChatConfig:
|
|
144
|
+
if ctx.args.editor:
|
|
145
|
+
check.arg(not ctx.args.interactive)
|
|
146
|
+
check.arg(not ctx.args.message)
|
|
147
|
+
raise NotImplementedError
|
|
148
|
+
|
|
149
|
+
if ctx.args.textual:
|
|
150
|
+
check.isinstance(cfg.interface, BareInterfaceConfig)
|
|
151
|
+
cfg = dc.replace(
|
|
152
|
+
cfg,
|
|
153
|
+
interface=TextualInterfaceConfig(**{
|
|
154
|
+
f.name: getattr(cfg.interface, f.name)
|
|
155
|
+
for f in dc.fields(InterfaceConfig)
|
|
156
|
+
}),
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
else:
|
|
160
|
+
cfg = dc.replace(
|
|
161
|
+
cfg,
|
|
162
|
+
driver=dc.replace(
|
|
163
|
+
cfg.driver,
|
|
164
|
+
ai=dc.replace(
|
|
165
|
+
cfg.driver.ai,
|
|
166
|
+
verbose=True,
|
|
167
|
+
),
|
|
168
|
+
),
|
|
169
|
+
interface=dc.replace(
|
|
170
|
+
check.isinstance(cfg.interface, BareInterfaceConfig),
|
|
171
|
+
interactive=ctx.args.interactive,
|
|
172
|
+
),
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
return cfg
|
|
176
|
+
|
|
177
|
+
#
|
|
178
|
+
|
|
179
|
+
class Input(ProfileAspect[ChatConfig]):
|
|
180
|
+
parser_args: ta.ClassVar[ta.Sequence[ap.Arg]] = [
|
|
181
|
+
ap.arg('message', nargs='*'),
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
def configure(self, ctx: ProfileAspect.ConfigureContext[ChatConfig], cfg: ChatConfig) -> ChatConfig:
|
|
185
|
+
if ctx.args.interactive or ctx.args.textual:
|
|
186
|
+
check.arg(not ctx.args.message)
|
|
187
|
+
|
|
188
|
+
elif ctx.args.message:
|
|
189
|
+
ps: list[str] = []
|
|
190
|
+
|
|
191
|
+
for a in ctx.args.message:
|
|
192
|
+
if a == '-':
|
|
193
|
+
ps.append(sys.stdin.read())
|
|
194
|
+
|
|
195
|
+
elif a.startswith('@'):
|
|
196
|
+
with open(a[1:]) as f:
|
|
197
|
+
ps.append(f.read())
|
|
198
|
+
|
|
199
|
+
else:
|
|
200
|
+
ps.append(a)
|
|
201
|
+
|
|
202
|
+
c = ' '.join(ps)
|
|
203
|
+
|
|
204
|
+
cfg = dc.replace(
|
|
205
|
+
cfg,
|
|
206
|
+
driver=dc.replace(
|
|
207
|
+
cfg.driver,
|
|
208
|
+
user=dc.replace(
|
|
209
|
+
cfg.driver.user,
|
|
210
|
+
initial_user_content=c,
|
|
211
|
+
),
|
|
212
|
+
),
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
else:
|
|
216
|
+
raise ValueError('Must specify input')
|
|
217
|
+
|
|
218
|
+
return cfg
|
|
219
|
+
|
|
220
|
+
#
|
|
221
|
+
|
|
222
|
+
class State(ProfileAspect[ChatConfig]):
|
|
223
|
+
parser_args: ta.ClassVar[ta.Sequence[ap.Arg]] = [
|
|
224
|
+
ap.arg('-n', '--new', action='store_true'),
|
|
225
|
+
ap.arg('--ephemeral', action='store_true'),
|
|
226
|
+
]
|
|
227
|
+
|
|
228
|
+
def configure(self, ctx: ProfileAspect.ConfigureContext[ChatConfig], cfg: ChatConfig) -> ChatConfig:
|
|
229
|
+
return dc.replace(
|
|
230
|
+
cfg,
|
|
231
|
+
driver=dc.replace(
|
|
232
|
+
cfg.driver,
|
|
233
|
+
state=dc.replace(
|
|
234
|
+
cfg.driver.state,
|
|
235
|
+
state='ephemeral' if ctx.args.ephemeral else 'new' if ctx.args.new else 'continue',
|
|
236
|
+
),
|
|
237
|
+
),
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
#
|
|
241
|
+
|
|
242
|
+
class Output(ProfileAspect[ChatConfig]):
|
|
243
|
+
parser_args: ta.ClassVar[ta.Sequence[ap.Arg]] = [
|
|
244
|
+
ap.arg('-s', '--stream', action='store_true'),
|
|
245
|
+
ap.arg('-M', '--markdown', action='store_true'),
|
|
246
|
+
]
|
|
247
|
+
|
|
248
|
+
def configure(self, ctx: ProfileAspect.ConfigureContext[ChatConfig], cfg: ChatConfig) -> ChatConfig:
|
|
249
|
+
return dc.replace(
|
|
250
|
+
cfg,
|
|
251
|
+
driver=dc.replace(
|
|
252
|
+
cfg.driver,
|
|
253
|
+
ai=dc.replace(
|
|
254
|
+
cfg.driver.ai,
|
|
255
|
+
stream=bool(ctx.args.stream),
|
|
256
|
+
),
|
|
257
|
+
),
|
|
258
|
+
rendering=dc.replace(
|
|
259
|
+
cfg.rendering,
|
|
260
|
+
markdown=bool(ctx.args.markdown),
|
|
261
|
+
),
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
#
|
|
265
|
+
|
|
266
|
+
class Tools(ProfileAspect[ChatConfig]):
|
|
267
|
+
parser_args: ta.ClassVar[ta.Sequence[ap.Arg]] = [
|
|
268
|
+
ap.arg('--enable-fs-tools', action='store_true'),
|
|
269
|
+
ap.arg('--enable-todo-tools', action='store_true'),
|
|
270
|
+
# ap.arg('--enable-unsafe-tools-do-not-use-lol', action='store_true'),
|
|
271
|
+
ap.arg('--enable-test-weather-tool', action='store_true'),
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
def configure_with_tools(
|
|
275
|
+
self,
|
|
276
|
+
ctx: ProfileAspect.ConfigureContext[ChatConfig],
|
|
277
|
+
cfg: ChatConfig,
|
|
278
|
+
enabled_tools: ta.Iterable[str],
|
|
279
|
+
) -> ChatConfig:
|
|
280
|
+
check.not_isinstance(enabled_tools, str)
|
|
281
|
+
|
|
282
|
+
return dc.replace(
|
|
283
|
+
cfg,
|
|
284
|
+
driver=dc.replace(
|
|
285
|
+
cfg.driver,
|
|
286
|
+
ai=dc.replace(
|
|
287
|
+
cfg.driver.ai,
|
|
288
|
+
enable_tools=True,
|
|
289
|
+
),
|
|
290
|
+
tools=dc.replace(
|
|
291
|
+
cfg.driver.tools,
|
|
292
|
+
enabled_tools={ # noqa
|
|
293
|
+
*(cfg.driver.tools.enabled_tools or []),
|
|
294
|
+
*enabled_tools,
|
|
295
|
+
},
|
|
296
|
+
),
|
|
297
|
+
),
|
|
298
|
+
interface=dc.replace(
|
|
299
|
+
cfg.interface,
|
|
300
|
+
enable_tools=True,
|
|
301
|
+
),
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
def configure(self, ctx: ProfileAspect.ConfigureContext[ChatConfig], cfg: ChatConfig) -> ChatConfig:
|
|
305
|
+
if not (
|
|
306
|
+
ctx.args.enable_fs_tools or
|
|
307
|
+
ctx.args.enable_todo_tools or
|
|
308
|
+
# ctx.args.enable_unsafe_tools_do_not_use_lol or
|
|
309
|
+
ctx.args.enable_test_weather_tool
|
|
310
|
+
):
|
|
311
|
+
return cfg
|
|
312
|
+
|
|
313
|
+
return self.configure_with_tools(ctx, cfg, {
|
|
314
|
+
*(['fs'] if ctx.args.enable_fs_tools else []),
|
|
315
|
+
*(['todo'] if ctx.args.enable_todo_tools else []),
|
|
316
|
+
*(['weather'] if ctx.args.enable_test_weather_tool else []),
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
#
|
|
320
|
+
|
|
321
|
+
class Code(ProfileAspect[ChatConfig]):
|
|
322
|
+
parser_args: ta.ClassVar[ta.Sequence[ap.Arg]] = [
|
|
323
|
+
ap.arg('-c', '--code', action='store_true'),
|
|
324
|
+
]
|
|
325
|
+
|
|
326
|
+
def configure_for_code(self, ctx: ProfileAspect.ConfigureContext[ChatConfig], cfg: ChatConfig) -> ChatConfig:
|
|
327
|
+
cfg = dc.replace(
|
|
328
|
+
cfg,
|
|
329
|
+
driver=dc.replace(
|
|
330
|
+
cfg.driver,
|
|
331
|
+
ai=dc.replace(
|
|
332
|
+
cfg.driver.ai,
|
|
333
|
+
enable_tools=True,
|
|
334
|
+
),
|
|
335
|
+
),
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
if ctx.args.new or ctx.args.ephemeral:
|
|
339
|
+
from ..minichain.lib.code.prompts import CODE_AGENT_SYSTEM_PROMPT
|
|
340
|
+
system_content = CODE_AGENT_SYSTEM_PROMPT
|
|
341
|
+
|
|
342
|
+
cfg = dc.replace(
|
|
343
|
+
cfg,
|
|
344
|
+
driver=dc.replace(
|
|
345
|
+
cfg.driver,
|
|
346
|
+
user=dc.replace(
|
|
347
|
+
cfg.driver.user,
|
|
348
|
+
initial_system_content=system_content,
|
|
349
|
+
),
|
|
350
|
+
),
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
return cfg
|
|
354
|
+
|
|
355
|
+
def configure(self, ctx: ProfileAspect.ConfigureContext[ChatConfig], cfg: ChatConfig) -> ChatConfig:
|
|
356
|
+
if not ctx.args.code:
|
|
357
|
+
return cfg
|
|
358
|
+
|
|
359
|
+
return self.configure_for_code(ctx, cfg)
|
|
360
|
+
|
|
361
|
+
#
|
|
362
|
+
|
|
363
|
+
def _build_aspects(self) -> ta.Sequence[ProfileAspect[ChatConfig]]:
|
|
364
|
+
return [
|
|
365
|
+
*super()._build_aspects(),
|
|
366
|
+
self.Backend(),
|
|
367
|
+
self.Interface(),
|
|
368
|
+
self.Input(),
|
|
369
|
+
self.State(),
|
|
370
|
+
self.Output(),
|
|
371
|
+
self.Tools(),
|
|
372
|
+
self.Code(),
|
|
373
|
+
]
|
|
374
|
+
|
|
375
|
+
def initial_config(self) -> ChatConfig:
|
|
376
|
+
return ChatConfig()
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
#
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
class CodeProfile(ChatProfile):
|
|
383
|
+
class Tools(ChatProfile.Tools):
|
|
384
|
+
parser_args: ta.ClassVar[ta.Sequence[ap.Arg]] = []
|
|
385
|
+
|
|
386
|
+
def configure(self, ctx: ProfileAspect.ConfigureContext[ChatConfig], cfg: ChatConfig) -> ChatConfig:
|
|
387
|
+
return self.configure_with_tools(ctx, cfg, {
|
|
388
|
+
'fs',
|
|
389
|
+
'todo',
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
class Code(ChatProfile.Code):
|
|
393
|
+
parser_args: ta.ClassVar[ta.Sequence[ap.Arg]] = []
|
|
394
|
+
|
|
395
|
+
def configure(self, ctx: ProfileAspect.ConfigureContext[ChatConfig], cfg: ChatConfig) -> ChatConfig:
|
|
396
|
+
return self.configure_for_code(ctx, cfg)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
##
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
class CompletionProfile(Profile):
|
|
403
|
+
def configure(self, argv: ta.Sequence[str]) -> SessionConfig:
|
|
404
|
+
parser = ap.ArgumentParser()
|
|
405
|
+
parser.add_argument('prompt', nargs='*')
|
|
406
|
+
parser.add_argument('-b', '--backend', default='openai')
|
|
407
|
+
args = parser.parse_args(argv)
|
|
408
|
+
|
|
409
|
+
content = ' '.join(args.prompt)
|
|
410
|
+
|
|
411
|
+
cfg = CompletionConfig(
|
|
412
|
+
content=check.non_empty_str(content),
|
|
413
|
+
backend=args.backend,
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
return cfg
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
##
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
class EmbedProfile(Profile):
|
|
423
|
+
def configure(self, argv: ta.Sequence[str]) -> SessionConfig:
|
|
424
|
+
parser = ap.ArgumentParser()
|
|
425
|
+
parser.add_argument('prompt', nargs='*')
|
|
426
|
+
parser.add_argument('-b', '--backend', default='openai')
|
|
427
|
+
args = parser.parse_args(argv)
|
|
428
|
+
|
|
429
|
+
content = ' '.join(args.prompt)
|
|
430
|
+
|
|
431
|
+
cfg = EmbeddingConfig(
|
|
432
|
+
content=check.non_empty_str(content),
|
|
433
|
+
backend=args.backend,
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
return cfg
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
##
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
PROFILE_TYPES: ta.Mapping[str, type[Profile]] = {
|
|
443
|
+
'chat': ChatProfile,
|
|
444
|
+
'code': CodeProfile,
|
|
445
|
+
|
|
446
|
+
'complete': CompletionProfile,
|
|
447
|
+
|
|
448
|
+
'embed': EmbedProfile,
|
|
449
|
+
}
|
|
@@ -16,6 +16,7 @@ from omlish.logs import all as logs
|
|
|
16
16
|
|
|
17
17
|
from ...... import minichain as mc
|
|
18
18
|
from .....backends.types import BackendName
|
|
19
|
+
from ....types import SessionProfileName
|
|
19
20
|
from ...drivers.events.types import AiDeltaChatEvent
|
|
20
21
|
from ...drivers.events.types import AiMessagesChatEvent
|
|
21
22
|
from ...drivers.types import ChatDriver
|
|
@@ -100,6 +101,7 @@ class ChatApp(
|
|
|
100
101
|
backend_name: BackendName | None = None,
|
|
101
102
|
devtools_setup: tx.DevtoolsSetup | None = None,
|
|
102
103
|
input_history_manager: InputHistoryManager,
|
|
104
|
+
session_profile_name: SessionProfileName | None = None,
|
|
103
105
|
) -> None:
|
|
104
106
|
super().__init__()
|
|
105
107
|
|
|
@@ -111,6 +113,7 @@ class ChatApp(
|
|
|
111
113
|
self._chat_event_queue = chat_event_queue
|
|
112
114
|
self._backend_name = backend_name
|
|
113
115
|
self._input_history_manager = input_history_manager
|
|
116
|
+
self._session_profile_name = session_profile_name
|
|
114
117
|
|
|
115
118
|
self._chat_action_queue: asyncio.Queue[ta.Any] = asyncio.Queue()
|
|
116
119
|
|
|
@@ -328,6 +331,7 @@ class ChatApp(
|
|
|
328
331
|
|
|
329
332
|
await self._mount_messages(
|
|
330
333
|
WelcomeMessage('\n'.join([
|
|
334
|
+
*([f'Profile: {self._session_profile_name}'] if self._session_profile_name is not None else []),
|
|
331
335
|
f'Backend: {self._backend_name or "?"}',
|
|
332
336
|
f'Dir: {os.getcwd()}',
|
|
333
337
|
])),
|
ommlds/cli/sessions/inject.py
CHANGED
|
@@ -5,6 +5,7 @@ from .chat.configs import ChatConfig
|
|
|
5
5
|
from .completion.configs import CompletionConfig
|
|
6
6
|
from .configs import SessionConfig
|
|
7
7
|
from .embedding.configs import EmbeddingConfig
|
|
8
|
+
from .types import SessionProfileName
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
with lang.auto_proxy_import(globals()):
|
|
@@ -16,11 +17,20 @@ with lang.auto_proxy_import(globals()):
|
|
|
16
17
|
##
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
def bind_sessions(
|
|
20
|
+
def bind_sessions(
|
|
21
|
+
cfg: SessionConfig,
|
|
22
|
+
*,
|
|
23
|
+
profile_name: str | None = None,
|
|
24
|
+
) -> inj.Elements:
|
|
20
25
|
els: list[inj.Elemental] = []
|
|
21
26
|
|
|
22
27
|
#
|
|
23
28
|
|
|
29
|
+
if profile_name is not None:
|
|
30
|
+
els.append(inj.bind(SessionProfileName, to_const=profile_name))
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
|
|
24
34
|
if isinstance(cfg, ChatConfig):
|
|
25
35
|
els.append(_chat.bind_chat(cfg))
|
|
26
36
|
|
ommlds/minichain/__init__.py
CHANGED
|
@@ -69,13 +69,15 @@ class TransformersTokenizer(tks.BaseTokenizer):
|
|
|
69
69
|
) -> list[tks.Token]:
|
|
70
70
|
ts = self._tfm_tokenizer.tokenize(text)
|
|
71
71
|
ids = self._tfm_tokenizer.convert_tokens_to_ids(ts)
|
|
72
|
-
return ids
|
|
72
|
+
return ta.cast('list[tks.Token]', ids)
|
|
73
73
|
|
|
74
74
|
def _decode(
|
|
75
75
|
self,
|
|
76
76
|
tokens: ta.Iterable[tks.Token],
|
|
77
77
|
) -> str:
|
|
78
|
-
|
|
78
|
+
if not isinstance(tokens, (tuple, list)): # Yes actually special cased by transformers
|
|
79
|
+
tokens = list(tokens)
|
|
80
|
+
return check.isinstance(self._tfm_tokenizer.decode(ta.cast('list[int]', tokens)), str)
|
|
79
81
|
|
|
80
82
|
|
|
81
83
|
##
|