ara-cli 0.1.9.95__py3-none-any.whl → 0.1.10.0__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.
- ara_cli/__init__.py +5 -2
- ara_cli/__main__.py +61 -13
- ara_cli/ara_command_action.py +85 -20
- ara_cli/ara_command_parser.py +42 -2
- ara_cli/ara_config.py +118 -94
- ara_cli/artefact_autofix.py +131 -2
- ara_cli/artefact_creator.py +2 -7
- ara_cli/artefact_deleter.py +2 -4
- ara_cli/artefact_fuzzy_search.py +13 -6
- ara_cli/artefact_models/artefact_templates.py +3 -3
- ara_cli/artefact_models/feature_artefact_model.py +25 -0
- ara_cli/artefact_reader.py +4 -5
- ara_cli/chat.py +210 -150
- ara_cli/commands/extract_command.py +4 -11
- ara_cli/error_handler.py +134 -0
- ara_cli/file_classifier.py +3 -2
- ara_cli/prompt_extractor.py +1 -1
- ara_cli/prompt_handler.py +268 -127
- ara_cli/template_loader.py +245 -0
- ara_cli/version.py +1 -1
- {ara_cli-0.1.9.95.dist-info → ara_cli-0.1.10.0.dist-info}/METADATA +2 -1
- {ara_cli-0.1.9.95.dist-info → ara_cli-0.1.10.0.dist-info}/RECORD +32 -29
- tests/test_ara_command_action.py +66 -52
- tests/test_artefact_autofix.py +361 -5
- tests/test_chat.py +1894 -546
- tests/test_file_classifier.py +23 -0
- tests/test_file_creator.py +3 -5
- tests/test_prompt_handler.py +40 -4
- tests/test_template_loader.py +192 -0
- {ara_cli-0.1.9.95.dist-info → ara_cli-0.1.10.0.dist-info}/WHEEL +0 -0
- {ara_cli-0.1.9.95.dist-info → ara_cli-0.1.10.0.dist-info}/entry_points.txt +0 -0
- {ara_cli-0.1.9.95.dist-info → ara_cli-0.1.10.0.dist-info}/top_level.txt +0 -0
ara_cli/chat.py
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import errno
|
|
2
3
|
import argparse
|
|
3
4
|
import cmd2
|
|
5
|
+
|
|
4
6
|
from ara_cli.prompt_handler import send_prompt
|
|
5
|
-
|
|
7
|
+
|
|
8
|
+
from . import error_handler
|
|
9
|
+
from ara_cli.error_handler import AraError, AraConfigurationError
|
|
6
10
|
|
|
7
11
|
from ara_cli.file_loaders.document_file_loader import DocumentFileLoader
|
|
8
12
|
from ara_cli.file_loaders.binary_file_loader import BinaryFileLoader
|
|
@@ -10,27 +14,42 @@ from ara_cli.file_loaders.text_file_loader import TextFileLoader
|
|
|
10
14
|
|
|
11
15
|
|
|
12
16
|
extract_parser = argparse.ArgumentParser()
|
|
13
|
-
extract_parser.add_argument(
|
|
14
|
-
|
|
17
|
+
extract_parser.add_argument(
|
|
18
|
+
"-f", "--force", action="store_true", help="Force extraction"
|
|
19
|
+
)
|
|
20
|
+
extract_parser.add_argument(
|
|
21
|
+
"-w",
|
|
22
|
+
"--write",
|
|
23
|
+
action="store_true",
|
|
24
|
+
help="Overwrite existing files without using LLM for merging.",
|
|
25
|
+
)
|
|
15
26
|
|
|
16
27
|
load_parser = argparse.ArgumentParser()
|
|
17
|
-
load_parser.add_argument(
|
|
18
|
-
load_parser.add_argument(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
from ara_cli.file_loaders.text_file_loader import TextFileLoader
|
|
24
|
-
|
|
28
|
+
load_parser.add_argument("file_name", nargs="?", default="", help="File to load")
|
|
29
|
+
load_parser.add_argument(
|
|
30
|
+
"--load-images",
|
|
31
|
+
action="store_true",
|
|
32
|
+
help="Extract and describe images from documents",
|
|
33
|
+
)
|
|
25
34
|
|
|
26
35
|
extract_parser = argparse.ArgumentParser()
|
|
27
|
-
extract_parser.add_argument(
|
|
28
|
-
|
|
36
|
+
extract_parser.add_argument(
|
|
37
|
+
"-f", "--force", action="store_true", help="Force extraction"
|
|
38
|
+
)
|
|
39
|
+
extract_parser.add_argument(
|
|
40
|
+
"-w",
|
|
41
|
+
"--write",
|
|
42
|
+
action="store_true",
|
|
43
|
+
help="Overwrite existing files without using LLM for merging.",
|
|
44
|
+
)
|
|
29
45
|
|
|
30
46
|
load_parser = argparse.ArgumentParser()
|
|
31
|
-
load_parser.add_argument(
|
|
32
|
-
load_parser.add_argument(
|
|
33
|
-
|
|
47
|
+
load_parser.add_argument("file_name", nargs="?", default="", help="File to load")
|
|
48
|
+
load_parser.add_argument(
|
|
49
|
+
"--load-images",
|
|
50
|
+
action="store_true",
|
|
51
|
+
help="Extract and describe images from documents",
|
|
52
|
+
)
|
|
34
53
|
|
|
35
54
|
|
|
36
55
|
class Chat(cmd2.Cmd):
|
|
@@ -60,36 +79,40 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
60
79
|
ROLE_RESPONSE = "ara response"
|
|
61
80
|
|
|
62
81
|
BINARY_TYPE_MAPPING = {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
".png": "image/png",
|
|
83
|
+
".jpg": "image/jpeg",
|
|
84
|
+
".jpeg": "image/jpeg",
|
|
85
|
+
}
|
|
86
|
+
|
|
68
87
|
DOCUMENT_TYPE_EXTENSIONS = [".docx", ".doc", ".odt", ".pdf"]
|
|
69
88
|
|
|
70
89
|
def __init__(
|
|
71
90
|
self,
|
|
72
91
|
chat_name: str,
|
|
73
92
|
reset: bool | None = None,
|
|
74
|
-
enable_commands: list[str] | None = None
|
|
93
|
+
enable_commands: list[str] | None = None,
|
|
75
94
|
):
|
|
95
|
+
from ara_cli.template_loader import TemplateLoader
|
|
76
96
|
shortcuts = dict(cmd2.DEFAULT_SHORTCUTS)
|
|
77
97
|
if enable_commands:
|
|
78
98
|
enable_commands.append("quit") # always allow quitting
|
|
79
99
|
enable_commands.append("eof") # always allow quitting with ctrl-D
|
|
80
100
|
enable_commands.append("help") # always allow help
|
|
81
101
|
|
|
82
|
-
shortcuts = {
|
|
102
|
+
shortcuts = {
|
|
103
|
+
key: value
|
|
104
|
+
for key, value in shortcuts.items()
|
|
105
|
+
if value in enable_commands
|
|
106
|
+
}
|
|
83
107
|
|
|
84
|
-
super().__init__(
|
|
85
|
-
allow_cli_args=False,
|
|
86
|
-
shortcuts=shortcuts
|
|
87
|
-
)
|
|
108
|
+
super().__init__(allow_cli_args=False, shortcuts=shortcuts)
|
|
88
109
|
self.create_default_aliases()
|
|
89
110
|
|
|
90
111
|
if enable_commands:
|
|
91
112
|
all_commands = self.get_all_commands()
|
|
92
|
-
commands_to_disable = [
|
|
113
|
+
commands_to_disable = [
|
|
114
|
+
command for command in all_commands if command not in enable_commands
|
|
115
|
+
]
|
|
93
116
|
self.disable_commands(commands_to_disable)
|
|
94
117
|
|
|
95
118
|
self.prompt = "ara> "
|
|
@@ -101,12 +124,15 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
101
124
|
self.chat_history = []
|
|
102
125
|
self.message_buffer = []
|
|
103
126
|
self.config = self._retrieve_ara_config()
|
|
127
|
+
self.template_loader = TemplateLoader(chat_instance=self)
|
|
104
128
|
|
|
105
129
|
def disable_commands(self, commands: list[str]):
|
|
106
130
|
for command in commands:
|
|
107
|
-
setattr(self, f
|
|
131
|
+
setattr(self, f"do_{command}", self.default)
|
|
108
132
|
self.hidden_commands.append(command)
|
|
109
|
-
aliases_to_remove = [
|
|
133
|
+
aliases_to_remove = [
|
|
134
|
+
alias for alias, cmd in self.aliases.items() if cmd in commands
|
|
135
|
+
]
|
|
110
136
|
for alias in aliases_to_remove:
|
|
111
137
|
del self.aliases[alias]
|
|
112
138
|
|
|
@@ -141,8 +167,10 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
141
167
|
chat_file_short = os.path.split(chat_file)[-1]
|
|
142
168
|
|
|
143
169
|
if reset is None:
|
|
144
|
-
user_input = input(
|
|
145
|
-
|
|
170
|
+
user_input = input(
|
|
171
|
+
f"{chat_file_short} already exists. Do you want to reset the chat? (y/N): "
|
|
172
|
+
)
|
|
173
|
+
if user_input.lower() == "y":
|
|
146
174
|
self.create_empty_chat_file(chat_file)
|
|
147
175
|
if reset:
|
|
148
176
|
self.create_empty_chat_file(chat_file)
|
|
@@ -175,10 +203,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
175
203
|
def get_last_role_marker(lines):
|
|
176
204
|
if not lines:
|
|
177
205
|
return
|
|
178
|
-
role_markers = [
|
|
179
|
-
f"# {Chat.ROLE_PROMPT}:",
|
|
180
|
-
f"# {Chat.ROLE_RESPONSE}"
|
|
181
|
-
]
|
|
206
|
+
role_markers = [f"# {Chat.ROLE_PROMPT}:", f"# {Chat.ROLE_RESPONSE}"]
|
|
182
207
|
for line in reversed(lines):
|
|
183
208
|
stripped_line = line.strip()
|
|
184
209
|
if stripped_line.startswith(tuple(role_markers)):
|
|
@@ -186,7 +211,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
186
211
|
return None
|
|
187
212
|
|
|
188
213
|
def start_non_interactive(self):
|
|
189
|
-
with open(self.chat_name,
|
|
214
|
+
with open(self.chat_name, "r", encoding="utf-8") as file:
|
|
190
215
|
content = file.read()
|
|
191
216
|
print(content)
|
|
192
217
|
|
|
@@ -221,7 +246,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
221
246
|
text_content = []
|
|
222
247
|
image_data_list = []
|
|
223
248
|
|
|
224
|
-
image_pattern = re.compile(r
|
|
249
|
+
image_pattern = re.compile(r"\((data:image/[^;]+;base64,.*?)\)")
|
|
225
250
|
|
|
226
251
|
for line in message.splitlines():
|
|
227
252
|
match = image_pattern.search(line)
|
|
@@ -231,13 +256,8 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
231
256
|
else:
|
|
232
257
|
text_content.append(line)
|
|
233
258
|
|
|
234
|
-
message_content = {
|
|
235
|
-
|
|
236
|
-
"text": '\n'.join(text_content)}
|
|
237
|
-
message = {
|
|
238
|
-
"role": role,
|
|
239
|
-
"content": [message_content]
|
|
240
|
-
}
|
|
259
|
+
message_content = {"type": "text", "text": "\n".join(text_content)}
|
|
260
|
+
message = {"role": role, "content": [message_content]}
|
|
241
261
|
message = append_images_to_message(message, image_data_list)
|
|
242
262
|
return message
|
|
243
263
|
|
|
@@ -250,7 +270,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
250
270
|
|
|
251
271
|
split_pattern = re.compile(f"({prompt_marker}|{response_marker})")
|
|
252
272
|
|
|
253
|
-
parts = re.split(split_pattern,
|
|
273
|
+
parts = re.split(split_pattern, "\n".join(self.chat_history))
|
|
254
274
|
|
|
255
275
|
all_prompts_and_responses = []
|
|
256
276
|
current = ""
|
|
@@ -284,7 +304,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
284
304
|
prompt_to_send = self.assemble_prompt()
|
|
285
305
|
role_marker = f"# {Chat.ROLE_RESPONSE}:"
|
|
286
306
|
|
|
287
|
-
with open(self.chat_name,
|
|
307
|
+
with open(self.chat_name, "a+", encoding="utf-8") as file:
|
|
288
308
|
last_line = self.get_last_line(file)
|
|
289
309
|
|
|
290
310
|
print(role_marker)
|
|
@@ -307,24 +327,24 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
307
327
|
|
|
308
328
|
def save_message(self, role: str, message: str):
|
|
309
329
|
role_marker = f"# {role}:"
|
|
310
|
-
with open(self.chat_name,
|
|
330
|
+
with open(self.chat_name, "r", encoding="utf-8") as file:
|
|
311
331
|
stripped_line = self.get_last_non_empty_line(file)
|
|
312
332
|
line_to_write = f"{message}\n\n"
|
|
313
333
|
if stripped_line != role_marker:
|
|
314
334
|
line_to_write = f"\n{role_marker}\n{message}\n"
|
|
315
335
|
|
|
316
|
-
with open(self.chat_name,
|
|
336
|
+
with open(self.chat_name, "a", encoding="utf-8") as file:
|
|
317
337
|
file.write(line_to_write)
|
|
318
338
|
self.chat_history.append(line_to_write)
|
|
319
339
|
|
|
320
340
|
def resend_message(self):
|
|
321
|
-
with open(self.chat_name,
|
|
341
|
+
with open(self.chat_name, "r", encoding="utf-8") as file:
|
|
322
342
|
lines = file.readlines()
|
|
323
343
|
if not lines:
|
|
324
344
|
return
|
|
325
345
|
index_to_remove = self.find_last_reply_index(lines)
|
|
326
346
|
if index_to_remove is not None:
|
|
327
|
-
with open(self.chat_name,
|
|
347
|
+
with open(self.chat_name, "w", encoding="utf-8") as file:
|
|
328
348
|
file.writelines(lines[:index_to_remove])
|
|
329
349
|
self.send_message()
|
|
330
350
|
|
|
@@ -339,45 +359,35 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
339
359
|
return index_to_remove
|
|
340
360
|
|
|
341
361
|
def append_strings(self, strings: list[str]):
|
|
342
|
-
output =
|
|
343
|
-
with open(self.chat_name,
|
|
344
|
-
file.write(output +
|
|
362
|
+
output = "\n".join(strings)
|
|
363
|
+
with open(self.chat_name, "a") as file:
|
|
364
|
+
file.write(output + "\n")
|
|
345
365
|
|
|
346
366
|
def load_chat_history(self, chat_file: str):
|
|
347
367
|
chat_history = []
|
|
348
368
|
if os.path.exists(chat_file):
|
|
349
|
-
with open(chat_file,
|
|
369
|
+
with open(chat_file, "r", encoding="utf-8") as file:
|
|
350
370
|
chat_history = file.readlines()
|
|
351
371
|
return chat_history
|
|
352
372
|
|
|
353
373
|
def create_empty_chat_file(self, chat_file: str):
|
|
354
|
-
with open(chat_file,
|
|
374
|
+
with open(chat_file, "w", encoding="utf-8") as file:
|
|
355
375
|
file.write(self.default_chat_content)
|
|
356
376
|
self.chat_history = []
|
|
357
377
|
|
|
358
378
|
def add_prompt_tag_if_needed(self, chat_file: str):
|
|
359
|
-
with open(chat_file,
|
|
379
|
+
with open(chat_file, "r", encoding="utf-8") as file:
|
|
360
380
|
lines = file.readlines()
|
|
361
381
|
prompt_tag = f"# {Chat.ROLE_PROMPT}:"
|
|
362
382
|
if Chat.get_last_role_marker(lines) == prompt_tag:
|
|
363
383
|
return
|
|
364
384
|
append = prompt_tag
|
|
365
385
|
last_line = lines[-1].strip()
|
|
366
|
-
if last_line != "" and last_line !=
|
|
386
|
+
if last_line != "" and last_line != "\n":
|
|
367
387
|
append = f"\n{append}"
|
|
368
|
-
with open(chat_file,
|
|
388
|
+
with open(chat_file, "a", encoding="utf-8") as file:
|
|
369
389
|
file.write(append)
|
|
370
390
|
|
|
371
|
-
def determine_file_path(self, file_name: str):
|
|
372
|
-
current_directory = os.path.dirname(self.chat_name)
|
|
373
|
-
file_path = os.path.join(current_directory, file_name)
|
|
374
|
-
if not os.path.exists(file_path):
|
|
375
|
-
file_path = file_name
|
|
376
|
-
if not os.path.exists(file_path):
|
|
377
|
-
print(f"File {file_name} not found")
|
|
378
|
-
return None
|
|
379
|
-
return file_path
|
|
380
|
-
|
|
381
391
|
# @file_exists_check
|
|
382
392
|
def load_text_file(
|
|
383
393
|
self,
|
|
@@ -385,7 +395,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
385
395
|
prefix: str = "",
|
|
386
396
|
suffix: str = "",
|
|
387
397
|
block_delimiter: str = "",
|
|
388
|
-
extract_images: bool = False
|
|
398
|
+
extract_images: bool = False,
|
|
389
399
|
):
|
|
390
400
|
loader = TextFileLoader(self)
|
|
391
401
|
return loader.load(
|
|
@@ -393,18 +403,15 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
393
403
|
prefix=prefix,
|
|
394
404
|
suffix=suffix,
|
|
395
405
|
block_delimiter=block_delimiter,
|
|
396
|
-
extract_images=extract_images
|
|
406
|
+
extract_images=extract_images,
|
|
397
407
|
)
|
|
398
408
|
|
|
399
409
|
# @file_exists_check
|
|
400
|
-
def load_binary_file(
|
|
410
|
+
def load_binary_file(
|
|
411
|
+
self, file_path, mime_type: str, prefix: str = "", suffix: str = ""
|
|
412
|
+
):
|
|
401
413
|
loader = BinaryFileLoader(self)
|
|
402
|
-
return loader.load(
|
|
403
|
-
file_path,
|
|
404
|
-
mime_type=mime_type,
|
|
405
|
-
prefix=prefix,
|
|
406
|
-
suffix=suffix
|
|
407
|
-
)
|
|
414
|
+
return loader.load(file_path, mime_type=mime_type, prefix=prefix, suffix=suffix)
|
|
408
415
|
|
|
409
416
|
def read_markdown(self, file_path: str, extract_images: bool = False) -> str:
|
|
410
417
|
"""Read markdown file and optionally extract/describe images"""
|
|
@@ -420,7 +427,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
420
427
|
prefix: str = "",
|
|
421
428
|
suffix: str = "",
|
|
422
429
|
block_delimiter: str = "```",
|
|
423
|
-
extract_images: bool = False
|
|
430
|
+
extract_images: bool = False,
|
|
424
431
|
):
|
|
425
432
|
loader = DocumentFileLoader(self)
|
|
426
433
|
return loader.load(
|
|
@@ -428,7 +435,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
428
435
|
prefix=prefix,
|
|
429
436
|
suffix=suffix,
|
|
430
437
|
block_delimiter=block_delimiter,
|
|
431
|
-
extract_images=extract_images
|
|
438
|
+
extract_images=extract_images,
|
|
432
439
|
)
|
|
433
440
|
|
|
434
441
|
def load_file(
|
|
@@ -437,7 +444,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
437
444
|
prefix: str = "",
|
|
438
445
|
suffix: str = "",
|
|
439
446
|
block_delimiter: str = "",
|
|
440
|
-
extract_images: bool = False
|
|
447
|
+
extract_images: bool = False,
|
|
441
448
|
):
|
|
442
449
|
binary_type_mapping = Chat.BINARY_TYPE_MAPPING
|
|
443
450
|
document_type_extensions = Chat.DOCUMENT_TYPE_EXTENSIONS
|
|
@@ -449,8 +456,9 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
449
456
|
file_type = mime_type
|
|
450
457
|
break
|
|
451
458
|
|
|
452
|
-
is_file_document = any(
|
|
453
|
-
|
|
459
|
+
is_file_document = any(
|
|
460
|
+
file_name_lower.endswith(ext) for ext in document_type_extensions
|
|
461
|
+
)
|
|
454
462
|
|
|
455
463
|
if is_file_document:
|
|
456
464
|
return self.load_document_file(
|
|
@@ -458,14 +466,11 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
458
466
|
prefix=prefix,
|
|
459
467
|
suffix=suffix,
|
|
460
468
|
block_delimiter=block_delimiter,
|
|
461
|
-
extract_images=extract_images
|
|
469
|
+
extract_images=extract_images,
|
|
462
470
|
)
|
|
463
471
|
elif file_type:
|
|
464
472
|
return self.load_binary_file(
|
|
465
|
-
file_path=file_name,
|
|
466
|
-
mime_type=file_type,
|
|
467
|
-
prefix=prefix,
|
|
468
|
-
suffix=suffix
|
|
473
|
+
file_path=file_name, mime_type=file_type, prefix=prefix, suffix=suffix
|
|
469
474
|
)
|
|
470
475
|
else:
|
|
471
476
|
return self.load_text_file(
|
|
@@ -473,7 +478,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
473
478
|
prefix=prefix,
|
|
474
479
|
suffix=suffix,
|
|
475
480
|
block_delimiter=block_delimiter,
|
|
476
|
-
extract_images=extract_images
|
|
481
|
+
extract_images=extract_images,
|
|
477
482
|
)
|
|
478
483
|
|
|
479
484
|
def choose_file_to_load(self, files: list[str], pattern: str):
|
|
@@ -485,11 +490,13 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
485
490
|
try:
|
|
486
491
|
choice_index = int(choice) - 1
|
|
487
492
|
if choice_index < 0 or choice_index >= len(files):
|
|
488
|
-
|
|
493
|
+
error_handler.report_error(
|
|
494
|
+
ValueError("Invalid choice. Aborting load.")
|
|
495
|
+
)
|
|
489
496
|
return None
|
|
490
497
|
file_path = files[choice_index]
|
|
491
|
-
except ValueError:
|
|
492
|
-
|
|
498
|
+
except ValueError as e:
|
|
499
|
+
error_handler.report_error(ValueError("Invalid input. Aborting load."))
|
|
493
500
|
return None
|
|
494
501
|
else:
|
|
495
502
|
file_path = files[0]
|
|
@@ -498,7 +505,9 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
498
505
|
def _help_menu(self, verbose: bool = False):
|
|
499
506
|
super()._help_menu(verbose)
|
|
500
507
|
if self.aliases:
|
|
501
|
-
aliases = [
|
|
508
|
+
aliases = [
|
|
509
|
+
f"{alias} -> {command}" for alias, command in self.aliases.items()
|
|
510
|
+
]
|
|
502
511
|
self._print_topics("Aliases", aliases, verbose)
|
|
503
512
|
|
|
504
513
|
def do_quit(self, _):
|
|
@@ -507,10 +516,19 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
507
516
|
self.last_result = True
|
|
508
517
|
return True
|
|
509
518
|
|
|
519
|
+
def onecmd(self, *args, **kwargs):
|
|
520
|
+
try:
|
|
521
|
+
return super().onecmd(*args, **kwargs)
|
|
522
|
+
except Exception as e:
|
|
523
|
+
error_handler.report_error(e)
|
|
524
|
+
return False
|
|
525
|
+
|
|
510
526
|
def onecmd_plus_hooks(self, line, orig_rl_history_length):
|
|
511
527
|
# store the full line for use with default()
|
|
512
528
|
self.full_input = line
|
|
513
|
-
return super().onecmd_plus_hooks(
|
|
529
|
+
return super().onecmd_plus_hooks(
|
|
530
|
+
line, orig_rl_history_length=orig_rl_history_length
|
|
531
|
+
)
|
|
514
532
|
|
|
515
533
|
def default(self, line):
|
|
516
534
|
self.message_buffer.append(self.full_input)
|
|
@@ -523,7 +541,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
523
541
|
|
|
524
542
|
file_name = args.file_name
|
|
525
543
|
load_images = args.load_images
|
|
526
|
-
|
|
544
|
+
|
|
527
545
|
matching_files = self.find_matching_files_to_load(file_name)
|
|
528
546
|
if not matching_files:
|
|
529
547
|
return
|
|
@@ -532,7 +550,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
532
550
|
block_delimiter = "```"
|
|
533
551
|
prefix = f"\nFile: {file_path}\n"
|
|
534
552
|
self.add_prompt_tag_if_needed(self.chat_name)
|
|
535
|
-
|
|
553
|
+
|
|
536
554
|
if not os.path.isdir(file_path):
|
|
537
555
|
command = LoadCommand(
|
|
538
556
|
chat_instance=self,
|
|
@@ -540,16 +558,18 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
540
558
|
prefix=prefix,
|
|
541
559
|
block_delimiter=block_delimiter,
|
|
542
560
|
extract_images=load_images,
|
|
543
|
-
output=self.poutput
|
|
561
|
+
output=self.poutput,
|
|
544
562
|
)
|
|
545
563
|
command.execute()
|
|
546
564
|
|
|
547
565
|
def complete_LOAD(self, text, line, begidx, endidx):
|
|
548
566
|
import glob
|
|
549
|
-
|
|
567
|
+
|
|
568
|
+
return [x for x in glob.glob(text + "*")]
|
|
550
569
|
|
|
551
570
|
def _retrieve_ara_config(self):
|
|
552
571
|
from ara_cli.prompt_handler import ConfigManager
|
|
572
|
+
|
|
553
573
|
return ConfigManager().get_config()
|
|
554
574
|
|
|
555
575
|
def _retrieve_llm_config(self):
|
|
@@ -565,7 +585,9 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
565
585
|
file_pattern = os.path.join(os.path.dirname(self.chat_name), file_name)
|
|
566
586
|
matching_files = glob.glob(file_pattern)
|
|
567
587
|
if not matching_files:
|
|
568
|
-
|
|
588
|
+
error_handler.report_error(
|
|
589
|
+
AraError(f"No files matching pattern '{file_name}' found.")
|
|
590
|
+
)
|
|
569
591
|
return
|
|
570
592
|
return matching_files
|
|
571
593
|
|
|
@@ -581,27 +603,29 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
581
603
|
|
|
582
604
|
if file_type:
|
|
583
605
|
return self.load_binary_file(
|
|
584
|
-
file_path=file_name,
|
|
585
|
-
mime_type=file_type,
|
|
586
|
-
prefix=prefix,
|
|
587
|
-
suffix=suffix
|
|
606
|
+
file_path=file_name, mime_type=file_type, prefix=prefix, suffix=suffix
|
|
588
607
|
)
|
|
589
|
-
|
|
608
|
+
error_handler.report_error(
|
|
609
|
+
AraError(f"File {file_name} not recognized as image, could not load")
|
|
610
|
+
)
|
|
590
611
|
|
|
591
612
|
def _verify_llm_choice(self, model_name):
|
|
592
613
|
llm_config = self._retrieve_llm_config()
|
|
593
614
|
models = [name for name in llm_config.keys()]
|
|
594
615
|
if model_name not in models:
|
|
595
|
-
|
|
616
|
+
error_handler.report_error(
|
|
617
|
+
AraConfigurationError(
|
|
618
|
+
f"Model {model_name} unavailable. Retrieve the list of available models using the LIST_MODELS command."
|
|
619
|
+
)
|
|
620
|
+
)
|
|
596
621
|
return False
|
|
597
622
|
return True
|
|
598
623
|
|
|
599
|
-
|
|
600
624
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
601
625
|
def do_LOAD_IMAGE(self, file_name):
|
|
602
626
|
"""Load an image file and append it to chat file. Can be given the file name in-line. Will attempt to find the file relative to chat file first, then treat the given path as absolute"""
|
|
603
627
|
from ara_cli.commands.load_image_command import LoadImageCommand
|
|
604
|
-
|
|
628
|
+
|
|
605
629
|
matching_files = self.find_matching_files_to_load(file_name)
|
|
606
630
|
if not matching_files:
|
|
607
631
|
return
|
|
@@ -609,7 +633,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
609
633
|
for file_path in matching_files:
|
|
610
634
|
prefix = f"\nFile: {file_path}\n"
|
|
611
635
|
self.add_prompt_tag_if_needed(self.chat_name)
|
|
612
|
-
|
|
636
|
+
|
|
613
637
|
if not os.path.isdir(file_path):
|
|
614
638
|
# Determine mime type
|
|
615
639
|
file_type = None
|
|
@@ -618,18 +642,22 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
618
642
|
if file_path_lower.endswith(extension):
|
|
619
643
|
file_type = mime_type
|
|
620
644
|
break
|
|
621
|
-
|
|
645
|
+
|
|
622
646
|
if file_type:
|
|
623
647
|
command = LoadImageCommand(
|
|
624
648
|
chat_instance=self,
|
|
625
649
|
file_path=file_path,
|
|
626
650
|
mime_type=file_type,
|
|
627
651
|
prefix=prefix,
|
|
628
|
-
output=self.poutput
|
|
652
|
+
output=self.poutput,
|
|
629
653
|
)
|
|
630
654
|
command.execute()
|
|
631
655
|
else:
|
|
632
|
-
|
|
656
|
+
error_handler.report_error(
|
|
657
|
+
AraError(
|
|
658
|
+
f"File {file_path} not recognized as image, could not load"
|
|
659
|
+
)
|
|
660
|
+
)
|
|
633
661
|
|
|
634
662
|
@cmd2.with_category(CATEGORY_LLM_CONTROL)
|
|
635
663
|
def do_LIST_MODELS(self, _):
|
|
@@ -648,7 +676,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
648
676
|
original_dir = os.getcwd()
|
|
649
677
|
navigator = DirectoryNavigator()
|
|
650
678
|
navigator.navigate_to_target()
|
|
651
|
-
os.chdir(
|
|
679
|
+
os.chdir("..")
|
|
652
680
|
|
|
653
681
|
if not self._verify_llm_choice(model_name):
|
|
654
682
|
return
|
|
@@ -670,14 +698,14 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
670
698
|
original_dir = os.getcwd()
|
|
671
699
|
navigator = DirectoryNavigator()
|
|
672
700
|
navigator.navigate_to_target()
|
|
673
|
-
os.chdir(
|
|
701
|
+
os.chdir("..")
|
|
674
702
|
|
|
675
703
|
if not self._verify_llm_choice(model_name):
|
|
676
704
|
return
|
|
677
705
|
|
|
678
706
|
self.config.extraction_llm = model_name
|
|
679
707
|
save_data(filepath=DEFAULT_CONFIG_LOCATION, config=self.config)
|
|
680
|
-
|
|
708
|
+
|
|
681
709
|
LLMSingleton.set_extraction_model(model_name)
|
|
682
710
|
print(f"Extraction model switched to '{model_name}'")
|
|
683
711
|
|
|
@@ -693,7 +721,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
693
721
|
def do_CURRENT_EXTRACTION_MODEL(self, _):
|
|
694
722
|
"""Displays the current extraction language model."""
|
|
695
723
|
from ara_cli.prompt_handler import LLMSingleton
|
|
696
|
-
|
|
724
|
+
|
|
697
725
|
print(LLMSingleton.get_extraction_model())
|
|
698
726
|
|
|
699
727
|
def _complete_llms(self, text, line, begidx, endidx):
|
|
@@ -731,7 +759,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
731
759
|
def do_CLEAR(self, _):
|
|
732
760
|
"""Clear the chat and the file containing it"""
|
|
733
761
|
user_input = input("Are you sure you want to clear the chat? (y/N): ")
|
|
734
|
-
if user_input.lower() !=
|
|
762
|
+
if user_input.lower() != "y":
|
|
735
763
|
return
|
|
736
764
|
self.create_empty_chat_file(self.chat_name)
|
|
737
765
|
self.chat_history = self.load_chat_history(self.chat_name)
|
|
@@ -740,24 +768,30 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
740
768
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
741
769
|
def do_LOAD_RULES(self, rules_name):
|
|
742
770
|
"""Load rules from ./prompt.data/*.rules.md or from a specified template directory if an argument is given. Specify global/<rules_template> to access globally defined rules templates"""
|
|
743
|
-
self.
|
|
771
|
+
self.template_loader.load_template(rules_name, "rules", self.chat_name, "*.rules.md")
|
|
744
772
|
|
|
745
773
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
746
774
|
def do_LOAD_INTENTION(self, intention_name):
|
|
747
775
|
"""Load intention from ./prompt.data/*.intention.md or from a specified template directory if an argument is given. Specify global/<intention_template> to access globally defined intention templates"""
|
|
748
|
-
self.
|
|
776
|
+
self.template_loader.load_template(intention_name, "intention", self.chat_name, "*.intention.md")
|
|
749
777
|
|
|
750
778
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
751
779
|
def do_LOAD_COMMANDS(self, commands_name):
|
|
752
780
|
"""Load commands from ./prompt.data/*.commands.md or from a specified template directory if an argument is given. Specify global/<commands_template> to access globally defined commands templates"""
|
|
753
|
-
self.
|
|
781
|
+
self.template_loader.load_template(commands_name, "commands", self.chat_name, "*.commands.md")
|
|
754
782
|
|
|
755
783
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
756
784
|
def do_LOAD_BLUEPRINT(self, blueprint_name):
|
|
757
785
|
"""Load specified blueprint. Specify global/<blueprint_name> to access globally defined blueprints"""
|
|
758
|
-
self.
|
|
786
|
+
self.template_loader.load_template(blueprint_name, "blueprint", self.chat_name)
|
|
759
787
|
|
|
760
|
-
def _load_helper(
|
|
788
|
+
def _load_helper(
|
|
789
|
+
self,
|
|
790
|
+
directory: str,
|
|
791
|
+
pattern: str,
|
|
792
|
+
file_type: str,
|
|
793
|
+
exclude_pattern: str | None = None,
|
|
794
|
+
):
|
|
761
795
|
import glob
|
|
762
796
|
|
|
763
797
|
directory_path = os.path.join(os.path.dirname(self.chat_name), directory)
|
|
@@ -770,7 +804,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
770
804
|
matching_files = list(set(matching_files) - set(exclude_files))
|
|
771
805
|
|
|
772
806
|
if not matching_files:
|
|
773
|
-
|
|
807
|
+
error_handler.report_error(AraError(f"No {file_type} file found."))
|
|
774
808
|
return
|
|
775
809
|
|
|
776
810
|
file_path = self.choose_file_to_load(matching_files, pattern)
|
|
@@ -787,10 +821,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
787
821
|
from ara_cli.ara_config import ConfigManager
|
|
788
822
|
from ara_cli.directory_navigator import DirectoryNavigator
|
|
789
823
|
|
|
790
|
-
plurals = {
|
|
791
|
-
"commands": "commands",
|
|
792
|
-
"rules": "rules"
|
|
793
|
-
}
|
|
824
|
+
plurals = {"commands": "commands", "rules": "rules"}
|
|
794
825
|
|
|
795
826
|
plural = f"{template_type}s"
|
|
796
827
|
if template_type in plurals:
|
|
@@ -798,7 +829,9 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
798
829
|
|
|
799
830
|
if template_name.startswith("global/"):
|
|
800
831
|
directory = f"{TemplatePathManager.get_template_base_path()}/prompt-modules/{plural}/"
|
|
801
|
-
self._load_helper(
|
|
832
|
+
self._load_helper(
|
|
833
|
+
directory, template_name.removeprefix("global/"), template_type
|
|
834
|
+
)
|
|
802
835
|
return
|
|
803
836
|
|
|
804
837
|
ara_config = ConfigManager.get_config()
|
|
@@ -812,7 +845,9 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
812
845
|
os.chdir(original_directory)
|
|
813
846
|
|
|
814
847
|
custom_prompt_templates_subdir = self.config.custom_prompt_templates_subdir
|
|
815
|
-
template_directory =
|
|
848
|
+
template_directory = (
|
|
849
|
+
f"{local_templates_path}/{custom_prompt_templates_subdir}/{plural}"
|
|
850
|
+
)
|
|
816
851
|
self._load_helper(template_directory, template_name, template_type)
|
|
817
852
|
|
|
818
853
|
def _load_template_helper(self, template_name, template_type, default_pattern):
|
|
@@ -820,7 +855,9 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
820
855
|
self._load_helper("prompt.data", default_pattern, template_type)
|
|
821
856
|
return
|
|
822
857
|
|
|
823
|
-
self._load_template_from_global_or_local(
|
|
858
|
+
self._load_template_from_global_or_local(
|
|
859
|
+
template_name=template_name, template_type=template_type
|
|
860
|
+
)
|
|
824
861
|
|
|
825
862
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
826
863
|
@cmd2.with_argparser(extract_parser)
|
|
@@ -833,7 +870,6 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
833
870
|
force=args.force,
|
|
834
871
|
write=args.write,
|
|
835
872
|
output=self.poutput,
|
|
836
|
-
error_output=self.perror
|
|
837
873
|
)
|
|
838
874
|
command.execute()
|
|
839
875
|
|
|
@@ -861,13 +897,18 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
861
897
|
if path:
|
|
862
898
|
return [path]
|
|
863
899
|
relative_path_for_error = os.path.join(base_directory, file_name)
|
|
864
|
-
|
|
900
|
+
error_handler.report_error(
|
|
901
|
+
AraError,
|
|
902
|
+
f"No givens file found at {relative_path_for_error} or {file_name}",
|
|
903
|
+
)
|
|
865
904
|
return []
|
|
866
905
|
|
|
867
906
|
# If no file_name, check for defaults
|
|
868
907
|
default_files_to_check = [
|
|
869
908
|
os.path.join(base_directory, "prompt.data", "config.prompt_givens.md"),
|
|
870
|
-
os.path.join(
|
|
909
|
+
os.path.join(
|
|
910
|
+
base_directory, "prompt.data", "config.prompt_global_givens.md"
|
|
911
|
+
),
|
|
871
912
|
]
|
|
872
913
|
existing_defaults = [f for f in default_files_to_check if os.path.exists(f)]
|
|
873
914
|
if existing_defaults:
|
|
@@ -878,11 +919,13 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
878
919
|
if not user_input:
|
|
879
920
|
self.poutput("Aborting.")
|
|
880
921
|
return []
|
|
881
|
-
|
|
922
|
+
|
|
882
923
|
path = resolve_path(user_input)
|
|
883
924
|
if path:
|
|
884
925
|
return [path]
|
|
885
|
-
|
|
926
|
+
error_handler.report_error(
|
|
927
|
+
AraError(f"No givens file found at {user_input}. Aborting.")
|
|
928
|
+
)
|
|
886
929
|
return []
|
|
887
930
|
|
|
888
931
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
@@ -892,7 +935,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
892
935
|
|
|
893
936
|
givens_files_to_process = self._find_givens_files(file_name)
|
|
894
937
|
if not givens_files_to_process:
|
|
895
|
-
|
|
938
|
+
error_handler.report_error(AraError("No givens files to load."))
|
|
896
939
|
return
|
|
897
940
|
|
|
898
941
|
for givens_path in givens_files_to_process:
|
|
@@ -900,7 +943,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
900
943
|
# from the markdown file. No directory change is needed.
|
|
901
944
|
content, _ = load_givens(givens_path)
|
|
902
945
|
|
|
903
|
-
with open(self.chat_name,
|
|
946
|
+
with open(self.chat_name, "a", encoding="utf-8") as chat_file:
|
|
904
947
|
chat_file.write(content)
|
|
905
948
|
|
|
906
949
|
self.poutput(f"Loaded files listed and marked in {givens_path}")
|
|
@@ -917,17 +960,20 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
917
960
|
"""Load artefact template"""
|
|
918
961
|
from ara_cli.artefact_models.artefact_templates import template_artefact_of_type
|
|
919
962
|
|
|
920
|
-
artefact = template_artefact_of_type(
|
|
963
|
+
artefact = template_artefact_of_type("".join(template_name))
|
|
921
964
|
if not artefact:
|
|
965
|
+
error_handler.report_error(
|
|
966
|
+
ValueError(f"No template for '{template_name}' found.")
|
|
967
|
+
)
|
|
922
968
|
return
|
|
923
969
|
write_content = artefact.serialize()
|
|
924
970
|
self.add_prompt_tag_if_needed(self.chat_name)
|
|
925
|
-
with open(self.chat_name,
|
|
971
|
+
with open(self.chat_name, "a", encoding="utf-8") as chat_file:
|
|
926
972
|
chat_file.write(write_content)
|
|
927
973
|
print(f"Loaded {template_name} artefact template")
|
|
928
974
|
|
|
929
975
|
def complete_LOAD_TEMPLATE(self, text, line, begidx, endidx):
|
|
930
|
-
return self._complete_classifiers(
|
|
976
|
+
return self._complete_classifiers(text, line, begidx, endidx)
|
|
931
977
|
|
|
932
978
|
def _complete_classifiers(self, text, line, begidx, endidx):
|
|
933
979
|
from ara_cli.classifier import Classifier
|
|
@@ -936,11 +982,12 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
936
982
|
if not text:
|
|
937
983
|
completions = classifiers
|
|
938
984
|
else:
|
|
939
|
-
completions = [
|
|
985
|
+
completions = [
|
|
986
|
+
classifier for classifier in classifiers if classifier.startswith(text)
|
|
987
|
+
]
|
|
940
988
|
|
|
941
989
|
return completions
|
|
942
990
|
|
|
943
|
-
|
|
944
991
|
def _get_plural_template_type(self, template_type: str) -> str:
|
|
945
992
|
"""Determines the plural form of a template type."""
|
|
946
993
|
plurals = {"commands": "commands", "rules": "rules"}
|
|
@@ -953,22 +1000,25 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
953
1000
|
"""
|
|
954
1001
|
current_dir = os.path.dirname(self.chat_name)
|
|
955
1002
|
while True:
|
|
956
|
-
if os.path.isdir(os.path.join(current_dir,
|
|
1003
|
+
if os.path.isdir(os.path.join(current_dir, "ara")):
|
|
957
1004
|
return current_dir
|
|
958
1005
|
parent_dir = os.path.dirname(current_dir)
|
|
959
1006
|
if parent_dir == current_dir: # Reached the filesystem root
|
|
960
1007
|
return None
|
|
961
1008
|
current_dir = parent_dir
|
|
962
1009
|
|
|
963
|
-
def _gather_templates_from_path(
|
|
1010
|
+
def _gather_templates_from_path(
|
|
1011
|
+
self, search_path: str, templates_set: set, prefix: str = ""
|
|
1012
|
+
):
|
|
964
1013
|
"""
|
|
965
1014
|
Scans a given path for items and adds them to the provided set,
|
|
966
1015
|
optionally prepending a prefix.
|
|
967
1016
|
"""
|
|
968
1017
|
import glob
|
|
1018
|
+
|
|
969
1019
|
if not os.path.isdir(search_path):
|
|
970
1020
|
return
|
|
971
|
-
for path in glob.glob(os.path.join(search_path,
|
|
1021
|
+
for path in glob.glob(os.path.join(search_path, "*")):
|
|
972
1022
|
templates_set.add(f"{prefix}{os.path.basename(path)}")
|
|
973
1023
|
|
|
974
1024
|
def _get_available_templates(self, template_type: str) -> list[str]:
|
|
@@ -992,8 +1042,12 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
992
1042
|
# 1. Find Global Templates
|
|
993
1043
|
try:
|
|
994
1044
|
global_base_path = TemplatePathManager.get_template_base_path()
|
|
995
|
-
global_template_dir = os.path.join(
|
|
996
|
-
|
|
1045
|
+
global_template_dir = os.path.join(
|
|
1046
|
+
global_base_path, "prompt-modules", plural_type
|
|
1047
|
+
)
|
|
1048
|
+
self._gather_templates_from_path(
|
|
1049
|
+
global_template_dir, templates, prefix="global/"
|
|
1050
|
+
)
|
|
997
1051
|
except Exception:
|
|
998
1052
|
pass # Silently ignore if global templates are not found
|
|
999
1053
|
|
|
@@ -1001,8 +1055,14 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
1001
1055
|
try:
|
|
1002
1056
|
project_root = self._find_project_root()
|
|
1003
1057
|
if project_root:
|
|
1004
|
-
local_templates_base = os.path.join(
|
|
1005
|
-
|
|
1058
|
+
local_templates_base = os.path.join(
|
|
1059
|
+
project_root, self.config.local_prompt_templates_dir
|
|
1060
|
+
)
|
|
1061
|
+
custom_dir = os.path.join(
|
|
1062
|
+
local_templates_base,
|
|
1063
|
+
self.config.custom_prompt_templates_subdir,
|
|
1064
|
+
plural_type,
|
|
1065
|
+
)
|
|
1006
1066
|
self._gather_templates_from_path(custom_dir, templates)
|
|
1007
1067
|
except Exception:
|
|
1008
1068
|
pass # Silently ignore if local templates cannot be resolved
|
|
@@ -1011,7 +1071,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
1011
1071
|
|
|
1012
1072
|
def _template_completer(self, text: str, template_type: str) -> list[str]:
|
|
1013
1073
|
"""Generic completer for different template types."""
|
|
1014
|
-
available_templates = self.
|
|
1074
|
+
available_templates = self.template_loader.get_available_templates(template_type, os.path.dirname(self.chat_name))
|
|
1015
1075
|
if not text:
|
|
1016
1076
|
return available_templates
|
|
1017
1077
|
return [t for t in available_templates if t.startswith(text)]
|
|
@@ -1030,4 +1090,4 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
1030
1090
|
|
|
1031
1091
|
def complete_LOAD_BLUEPRINT(self, text, line, begidx, endidx):
|
|
1032
1092
|
"""Completer for the LOAD_BLUEPRINT command."""
|
|
1033
|
-
return self._template_completer(text, "blueprint")
|
|
1093
|
+
return self._template_completer(text, "blueprint")
|