ara-cli 0.1.9.96__py3-none-any.whl → 0.1.10.1__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 ara-cli might be problematic. Click here for more details.
- ara_cli/__init__.py +1 -1
- ara_cli/__main__.py +141 -103
- ara_cli/ara_command_action.py +65 -7
- ara_cli/ara_config.py +118 -94
- ara_cli/ara_subcommands/__init__.py +0 -0
- ara_cli/ara_subcommands/autofix.py +26 -0
- ara_cli/ara_subcommands/chat.py +27 -0
- ara_cli/ara_subcommands/classifier_directory.py +16 -0
- ara_cli/ara_subcommands/common.py +100 -0
- ara_cli/ara_subcommands/create.py +75 -0
- ara_cli/ara_subcommands/delete.py +22 -0
- ara_cli/ara_subcommands/extract.py +22 -0
- ara_cli/ara_subcommands/fetch_templates.py +14 -0
- ara_cli/ara_subcommands/list.py +65 -0
- ara_cli/ara_subcommands/list_tags.py +25 -0
- ara_cli/ara_subcommands/load.py +48 -0
- ara_cli/ara_subcommands/prompt.py +136 -0
- ara_cli/ara_subcommands/read.py +47 -0
- ara_cli/ara_subcommands/read_status.py +20 -0
- ara_cli/ara_subcommands/read_user.py +20 -0
- ara_cli/ara_subcommands/reconnect.py +27 -0
- ara_cli/ara_subcommands/rename.py +22 -0
- ara_cli/ara_subcommands/scan.py +14 -0
- ara_cli/ara_subcommands/set_status.py +22 -0
- ara_cli/ara_subcommands/set_user.py +22 -0
- ara_cli/ara_subcommands/template.py +16 -0
- ara_cli/artefact_models/artefact_model.py +88 -19
- ara_cli/artefact_models/artefact_templates.py +18 -9
- ara_cli/artefact_models/userstory_artefact_model.py +2 -2
- ara_cli/artefact_scan.py +2 -2
- ara_cli/chat.py +204 -142
- ara_cli/commands/read_command.py +17 -4
- ara_cli/completers.py +144 -0
- ara_cli/prompt_handler.py +268 -127
- ara_cli/tag_extractor.py +33 -16
- ara_cli/template_loader.py +245 -0
- ara_cli/version.py +1 -1
- {ara_cli-0.1.9.96.dist-info → ara_cli-0.1.10.1.dist-info}/METADATA +3 -1
- {ara_cli-0.1.9.96.dist-info → ara_cli-0.1.10.1.dist-info}/RECORD +47 -23
- tests/test_artefact_scan.py +1 -1
- tests/test_chat.py +1840 -574
- tests/test_prompt_handler.py +40 -4
- tests/test_tag_extractor.py +19 -13
- tests/test_template_loader.py +192 -0
- ara_cli/ara_command_parser.py +0 -565
- {ara_cli-0.1.9.96.dist-info → ara_cli-0.1.10.1.dist-info}/WHEEL +0 -0
- {ara_cli-0.1.9.96.dist-info → ara_cli-0.1.10.1.dist-info}/entry_points.txt +0 -0
- {ara_cli-0.1.9.96.dist-info → ara_cli-0.1.10.1.dist-info}/top_level.txt +0 -0
ara_cli/chat.py
CHANGED
|
@@ -1,29 +1,55 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import errno
|
|
2
3
|
import argparse
|
|
3
4
|
import cmd2
|
|
4
|
-
|
|
5
|
+
|
|
5
6
|
from ara_cli.prompt_handler import send_prompt
|
|
6
7
|
|
|
8
|
+
from . import error_handler
|
|
9
|
+
from ara_cli.error_handler import AraError, AraConfigurationError
|
|
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
|
|
9
13
|
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(
|
|
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
|
+
)
|
|
19
34
|
|
|
20
35
|
extract_parser = argparse.ArgumentParser()
|
|
21
|
-
extract_parser.add_argument(
|
|
22
|
-
|
|
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
|
+
)
|
|
23
45
|
|
|
24
46
|
load_parser = argparse.ArgumentParser()
|
|
25
|
-
load_parser.add_argument(
|
|
26
|
-
load_parser.add_argument(
|
|
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
|
+
)
|
|
27
53
|
|
|
28
54
|
|
|
29
55
|
class Chat(cmd2.Cmd):
|
|
@@ -53,10 +79,10 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
53
79
|
ROLE_RESPONSE = "ara response"
|
|
54
80
|
|
|
55
81
|
BINARY_TYPE_MAPPING = {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
82
|
+
".png": "image/png",
|
|
83
|
+
".jpg": "image/jpeg",
|
|
84
|
+
".jpeg": "image/jpeg",
|
|
85
|
+
}
|
|
60
86
|
|
|
61
87
|
DOCUMENT_TYPE_EXTENSIONS = [".docx", ".doc", ".odt", ".pdf"]
|
|
62
88
|
|
|
@@ -64,25 +90,29 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
64
90
|
self,
|
|
65
91
|
chat_name: str,
|
|
66
92
|
reset: bool | None = None,
|
|
67
|
-
enable_commands: list[str] | None = None
|
|
93
|
+
enable_commands: list[str] | None = None,
|
|
68
94
|
):
|
|
95
|
+
from ara_cli.template_loader import TemplateLoader
|
|
69
96
|
shortcuts = dict(cmd2.DEFAULT_SHORTCUTS)
|
|
70
97
|
if enable_commands:
|
|
71
98
|
enable_commands.append("quit") # always allow quitting
|
|
72
99
|
enable_commands.append("eof") # always allow quitting with ctrl-D
|
|
73
100
|
enable_commands.append("help") # always allow help
|
|
74
101
|
|
|
75
|
-
shortcuts = {
|
|
102
|
+
shortcuts = {
|
|
103
|
+
key: value
|
|
104
|
+
for key, value in shortcuts.items()
|
|
105
|
+
if value in enable_commands
|
|
106
|
+
}
|
|
76
107
|
|
|
77
|
-
super().__init__(
|
|
78
|
-
allow_cli_args=False,
|
|
79
|
-
shortcuts=shortcuts
|
|
80
|
-
)
|
|
108
|
+
super().__init__(allow_cli_args=False, shortcuts=shortcuts)
|
|
81
109
|
self.create_default_aliases()
|
|
82
110
|
|
|
83
111
|
if enable_commands:
|
|
84
112
|
all_commands = self.get_all_commands()
|
|
85
|
-
commands_to_disable = [
|
|
113
|
+
commands_to_disable = [
|
|
114
|
+
command for command in all_commands if command not in enable_commands
|
|
115
|
+
]
|
|
86
116
|
self.disable_commands(commands_to_disable)
|
|
87
117
|
|
|
88
118
|
self.prompt = "ara> "
|
|
@@ -94,12 +124,15 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
94
124
|
self.chat_history = []
|
|
95
125
|
self.message_buffer = []
|
|
96
126
|
self.config = self._retrieve_ara_config()
|
|
127
|
+
self.template_loader = TemplateLoader(chat_instance=self)
|
|
97
128
|
|
|
98
129
|
def disable_commands(self, commands: list[str]):
|
|
99
130
|
for command in commands:
|
|
100
|
-
setattr(self, f
|
|
131
|
+
setattr(self, f"do_{command}", self.default)
|
|
101
132
|
self.hidden_commands.append(command)
|
|
102
|
-
aliases_to_remove = [
|
|
133
|
+
aliases_to_remove = [
|
|
134
|
+
alias for alias, cmd in self.aliases.items() if cmd in commands
|
|
135
|
+
]
|
|
103
136
|
for alias in aliases_to_remove:
|
|
104
137
|
del self.aliases[alias]
|
|
105
138
|
|
|
@@ -134,8 +167,10 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
134
167
|
chat_file_short = os.path.split(chat_file)[-1]
|
|
135
168
|
|
|
136
169
|
if reset is None:
|
|
137
|
-
user_input = input(
|
|
138
|
-
|
|
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":
|
|
139
174
|
self.create_empty_chat_file(chat_file)
|
|
140
175
|
if reset:
|
|
141
176
|
self.create_empty_chat_file(chat_file)
|
|
@@ -168,10 +203,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
168
203
|
def get_last_role_marker(lines):
|
|
169
204
|
if not lines:
|
|
170
205
|
return
|
|
171
|
-
role_markers = [
|
|
172
|
-
f"# {Chat.ROLE_PROMPT}:",
|
|
173
|
-
f"# {Chat.ROLE_RESPONSE}"
|
|
174
|
-
]
|
|
206
|
+
role_markers = [f"# {Chat.ROLE_PROMPT}:", f"# {Chat.ROLE_RESPONSE}"]
|
|
175
207
|
for line in reversed(lines):
|
|
176
208
|
stripped_line = line.strip()
|
|
177
209
|
if stripped_line.startswith(tuple(role_markers)):
|
|
@@ -179,7 +211,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
179
211
|
return None
|
|
180
212
|
|
|
181
213
|
def start_non_interactive(self):
|
|
182
|
-
with open(self.chat_name,
|
|
214
|
+
with open(self.chat_name, "r", encoding="utf-8") as file:
|
|
183
215
|
content = file.read()
|
|
184
216
|
print(content)
|
|
185
217
|
|
|
@@ -214,7 +246,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
214
246
|
text_content = []
|
|
215
247
|
image_data_list = []
|
|
216
248
|
|
|
217
|
-
image_pattern = re.compile(r
|
|
249
|
+
image_pattern = re.compile(r"\((data:image/[^;]+;base64,.*?)\)")
|
|
218
250
|
|
|
219
251
|
for line in message.splitlines():
|
|
220
252
|
match = image_pattern.search(line)
|
|
@@ -224,13 +256,8 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
224
256
|
else:
|
|
225
257
|
text_content.append(line)
|
|
226
258
|
|
|
227
|
-
message_content = {
|
|
228
|
-
|
|
229
|
-
"text": '\n'.join(text_content)}
|
|
230
|
-
message = {
|
|
231
|
-
"role": role,
|
|
232
|
-
"content": [message_content]
|
|
233
|
-
}
|
|
259
|
+
message_content = {"type": "text", "text": "\n".join(text_content)}
|
|
260
|
+
message = {"role": role, "content": [message_content]}
|
|
234
261
|
message = append_images_to_message(message, image_data_list)
|
|
235
262
|
return message
|
|
236
263
|
|
|
@@ -243,7 +270,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
243
270
|
|
|
244
271
|
split_pattern = re.compile(f"({prompt_marker}|{response_marker})")
|
|
245
272
|
|
|
246
|
-
parts = re.split(split_pattern,
|
|
273
|
+
parts = re.split(split_pattern, "\n".join(self.chat_history))
|
|
247
274
|
|
|
248
275
|
all_prompts_and_responses = []
|
|
249
276
|
current = ""
|
|
@@ -277,7 +304,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
277
304
|
prompt_to_send = self.assemble_prompt()
|
|
278
305
|
role_marker = f"# {Chat.ROLE_RESPONSE}:"
|
|
279
306
|
|
|
280
|
-
with open(self.chat_name,
|
|
307
|
+
with open(self.chat_name, "a+", encoding="utf-8") as file:
|
|
281
308
|
last_line = self.get_last_line(file)
|
|
282
309
|
|
|
283
310
|
print(role_marker)
|
|
@@ -300,24 +327,24 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
300
327
|
|
|
301
328
|
def save_message(self, role: str, message: str):
|
|
302
329
|
role_marker = f"# {role}:"
|
|
303
|
-
with open(self.chat_name,
|
|
330
|
+
with open(self.chat_name, "r", encoding="utf-8") as file:
|
|
304
331
|
stripped_line = self.get_last_non_empty_line(file)
|
|
305
332
|
line_to_write = f"{message}\n\n"
|
|
306
333
|
if stripped_line != role_marker:
|
|
307
334
|
line_to_write = f"\n{role_marker}\n{message}\n"
|
|
308
335
|
|
|
309
|
-
with open(self.chat_name,
|
|
336
|
+
with open(self.chat_name, "a", encoding="utf-8") as file:
|
|
310
337
|
file.write(line_to_write)
|
|
311
338
|
self.chat_history.append(line_to_write)
|
|
312
339
|
|
|
313
340
|
def resend_message(self):
|
|
314
|
-
with open(self.chat_name,
|
|
341
|
+
with open(self.chat_name, "r", encoding="utf-8") as file:
|
|
315
342
|
lines = file.readlines()
|
|
316
343
|
if not lines:
|
|
317
344
|
return
|
|
318
345
|
index_to_remove = self.find_last_reply_index(lines)
|
|
319
346
|
if index_to_remove is not None:
|
|
320
|
-
with open(self.chat_name,
|
|
347
|
+
with open(self.chat_name, "w", encoding="utf-8") as file:
|
|
321
348
|
file.writelines(lines[:index_to_remove])
|
|
322
349
|
self.send_message()
|
|
323
350
|
|
|
@@ -332,45 +359,35 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
332
359
|
return index_to_remove
|
|
333
360
|
|
|
334
361
|
def append_strings(self, strings: list[str]):
|
|
335
|
-
output =
|
|
336
|
-
with open(self.chat_name,
|
|
337
|
-
file.write(output +
|
|
362
|
+
output = "\n".join(strings)
|
|
363
|
+
with open(self.chat_name, "a") as file:
|
|
364
|
+
file.write(output + "\n")
|
|
338
365
|
|
|
339
366
|
def load_chat_history(self, chat_file: str):
|
|
340
367
|
chat_history = []
|
|
341
368
|
if os.path.exists(chat_file):
|
|
342
|
-
with open(chat_file,
|
|
369
|
+
with open(chat_file, "r", encoding="utf-8") as file:
|
|
343
370
|
chat_history = file.readlines()
|
|
344
371
|
return chat_history
|
|
345
372
|
|
|
346
373
|
def create_empty_chat_file(self, chat_file: str):
|
|
347
|
-
with open(chat_file,
|
|
374
|
+
with open(chat_file, "w", encoding="utf-8") as file:
|
|
348
375
|
file.write(self.default_chat_content)
|
|
349
376
|
self.chat_history = []
|
|
350
377
|
|
|
351
378
|
def add_prompt_tag_if_needed(self, chat_file: str):
|
|
352
|
-
with open(chat_file,
|
|
379
|
+
with open(chat_file, "r", encoding="utf-8") as file:
|
|
353
380
|
lines = file.readlines()
|
|
354
381
|
prompt_tag = f"# {Chat.ROLE_PROMPT}:"
|
|
355
382
|
if Chat.get_last_role_marker(lines) == prompt_tag:
|
|
356
383
|
return
|
|
357
384
|
append = prompt_tag
|
|
358
385
|
last_line = lines[-1].strip()
|
|
359
|
-
if last_line != "" and last_line !=
|
|
386
|
+
if last_line != "" and last_line != "\n":
|
|
360
387
|
append = f"\n{append}"
|
|
361
|
-
with open(chat_file,
|
|
388
|
+
with open(chat_file, "a", encoding="utf-8") as file:
|
|
362
389
|
file.write(append)
|
|
363
390
|
|
|
364
|
-
def determine_file_path(self, file_name: str):
|
|
365
|
-
current_directory = os.path.dirname(self.chat_name)
|
|
366
|
-
file_path = os.path.join(current_directory, file_name)
|
|
367
|
-
if not os.path.exists(file_path):
|
|
368
|
-
file_path = file_name
|
|
369
|
-
if not os.path.exists(file_path):
|
|
370
|
-
print(f"File {file_name} not found")
|
|
371
|
-
return None
|
|
372
|
-
return file_path
|
|
373
|
-
|
|
374
391
|
# @file_exists_check
|
|
375
392
|
def load_text_file(
|
|
376
393
|
self,
|
|
@@ -378,7 +395,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
378
395
|
prefix: str = "",
|
|
379
396
|
suffix: str = "",
|
|
380
397
|
block_delimiter: str = "",
|
|
381
|
-
extract_images: bool = False
|
|
398
|
+
extract_images: bool = False,
|
|
382
399
|
):
|
|
383
400
|
loader = TextFileLoader(self)
|
|
384
401
|
return loader.load(
|
|
@@ -386,18 +403,15 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
386
403
|
prefix=prefix,
|
|
387
404
|
suffix=suffix,
|
|
388
405
|
block_delimiter=block_delimiter,
|
|
389
|
-
extract_images=extract_images
|
|
406
|
+
extract_images=extract_images,
|
|
390
407
|
)
|
|
391
408
|
|
|
392
409
|
# @file_exists_check
|
|
393
|
-
def load_binary_file(
|
|
410
|
+
def load_binary_file(
|
|
411
|
+
self, file_path, mime_type: str, prefix: str = "", suffix: str = ""
|
|
412
|
+
):
|
|
394
413
|
loader = BinaryFileLoader(self)
|
|
395
|
-
return loader.load(
|
|
396
|
-
file_path,
|
|
397
|
-
mime_type=mime_type,
|
|
398
|
-
prefix=prefix,
|
|
399
|
-
suffix=suffix
|
|
400
|
-
)
|
|
414
|
+
return loader.load(file_path, mime_type=mime_type, prefix=prefix, suffix=suffix)
|
|
401
415
|
|
|
402
416
|
def read_markdown(self, file_path: str, extract_images: bool = False) -> str:
|
|
403
417
|
"""Read markdown file and optionally extract/describe images"""
|
|
@@ -413,7 +427,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
413
427
|
prefix: str = "",
|
|
414
428
|
suffix: str = "",
|
|
415
429
|
block_delimiter: str = "```",
|
|
416
|
-
extract_images: bool = False
|
|
430
|
+
extract_images: bool = False,
|
|
417
431
|
):
|
|
418
432
|
loader = DocumentFileLoader(self)
|
|
419
433
|
return loader.load(
|
|
@@ -421,7 +435,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
421
435
|
prefix=prefix,
|
|
422
436
|
suffix=suffix,
|
|
423
437
|
block_delimiter=block_delimiter,
|
|
424
|
-
extract_images=extract_images
|
|
438
|
+
extract_images=extract_images,
|
|
425
439
|
)
|
|
426
440
|
|
|
427
441
|
def load_file(
|
|
@@ -430,7 +444,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
430
444
|
prefix: str = "",
|
|
431
445
|
suffix: str = "",
|
|
432
446
|
block_delimiter: str = "",
|
|
433
|
-
extract_images: bool = False
|
|
447
|
+
extract_images: bool = False,
|
|
434
448
|
):
|
|
435
449
|
binary_type_mapping = Chat.BINARY_TYPE_MAPPING
|
|
436
450
|
document_type_extensions = Chat.DOCUMENT_TYPE_EXTENSIONS
|
|
@@ -442,8 +456,9 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
442
456
|
file_type = mime_type
|
|
443
457
|
break
|
|
444
458
|
|
|
445
|
-
is_file_document = any(
|
|
446
|
-
|
|
459
|
+
is_file_document = any(
|
|
460
|
+
file_name_lower.endswith(ext) for ext in document_type_extensions
|
|
461
|
+
)
|
|
447
462
|
|
|
448
463
|
if is_file_document:
|
|
449
464
|
return self.load_document_file(
|
|
@@ -451,14 +466,11 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
451
466
|
prefix=prefix,
|
|
452
467
|
suffix=suffix,
|
|
453
468
|
block_delimiter=block_delimiter,
|
|
454
|
-
extract_images=extract_images
|
|
469
|
+
extract_images=extract_images,
|
|
455
470
|
)
|
|
456
471
|
elif file_type:
|
|
457
472
|
return self.load_binary_file(
|
|
458
|
-
file_path=file_name,
|
|
459
|
-
mime_type=file_type,
|
|
460
|
-
prefix=prefix,
|
|
461
|
-
suffix=suffix
|
|
473
|
+
file_path=file_name, mime_type=file_type, prefix=prefix, suffix=suffix
|
|
462
474
|
)
|
|
463
475
|
else:
|
|
464
476
|
return self.load_text_file(
|
|
@@ -466,7 +478,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
466
478
|
prefix=prefix,
|
|
467
479
|
suffix=suffix,
|
|
468
480
|
block_delimiter=block_delimiter,
|
|
469
|
-
extract_images=extract_images
|
|
481
|
+
extract_images=extract_images,
|
|
470
482
|
)
|
|
471
483
|
|
|
472
484
|
def choose_file_to_load(self, files: list[str], pattern: str):
|
|
@@ -478,11 +490,13 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
478
490
|
try:
|
|
479
491
|
choice_index = int(choice) - 1
|
|
480
492
|
if choice_index < 0 or choice_index >= len(files):
|
|
481
|
-
|
|
493
|
+
error_handler.report_error(
|
|
494
|
+
ValueError("Invalid choice. Aborting load.")
|
|
495
|
+
)
|
|
482
496
|
return None
|
|
483
497
|
file_path = files[choice_index]
|
|
484
|
-
except ValueError:
|
|
485
|
-
|
|
498
|
+
except ValueError as e:
|
|
499
|
+
error_handler.report_error(ValueError("Invalid input. Aborting load."))
|
|
486
500
|
return None
|
|
487
501
|
else:
|
|
488
502
|
file_path = files[0]
|
|
@@ -491,7 +505,9 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
491
505
|
def _help_menu(self, verbose: bool = False):
|
|
492
506
|
super()._help_menu(verbose)
|
|
493
507
|
if self.aliases:
|
|
494
|
-
aliases = [
|
|
508
|
+
aliases = [
|
|
509
|
+
f"{alias} -> {command}" for alias, command in self.aliases.items()
|
|
510
|
+
]
|
|
495
511
|
self._print_topics("Aliases", aliases, verbose)
|
|
496
512
|
|
|
497
513
|
def do_quit(self, _):
|
|
@@ -510,7 +526,9 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
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,33 +759,40 @@ 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)
|
|
766
|
+
self.message_buffer.clear()
|
|
738
767
|
print(f"Cleared content of {self.chat_name}")
|
|
739
768
|
|
|
740
769
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
741
770
|
def do_LOAD_RULES(self, rules_name):
|
|
742
771
|
"""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.
|
|
772
|
+
self.template_loader.load_template(rules_name, "rules", self.chat_name, "*.rules.md")
|
|
744
773
|
|
|
745
774
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
746
775
|
def do_LOAD_INTENTION(self, intention_name):
|
|
747
776
|
"""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.
|
|
777
|
+
self.template_loader.load_template(intention_name, "intention", self.chat_name, "*.intention.md")
|
|
749
778
|
|
|
750
779
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
751
780
|
def do_LOAD_COMMANDS(self, commands_name):
|
|
752
781
|
"""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.
|
|
782
|
+
self.template_loader.load_template(commands_name, "commands", self.chat_name, "*.commands.md")
|
|
754
783
|
|
|
755
784
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
756
785
|
def do_LOAD_BLUEPRINT(self, blueprint_name):
|
|
757
786
|
"""Load specified blueprint. Specify global/<blueprint_name> to access globally defined blueprints"""
|
|
758
|
-
self.
|
|
787
|
+
self.template_loader.load_template(blueprint_name, "blueprint", self.chat_name)
|
|
759
788
|
|
|
760
|
-
def _load_helper(
|
|
789
|
+
def _load_helper(
|
|
790
|
+
self,
|
|
791
|
+
directory: str,
|
|
792
|
+
pattern: str,
|
|
793
|
+
file_type: str,
|
|
794
|
+
exclude_pattern: str | None = None,
|
|
795
|
+
):
|
|
761
796
|
import glob
|
|
762
797
|
|
|
763
798
|
directory_path = os.path.join(os.path.dirname(self.chat_name), directory)
|
|
@@ -770,7 +805,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
770
805
|
matching_files = list(set(matching_files) - set(exclude_files))
|
|
771
806
|
|
|
772
807
|
if not matching_files:
|
|
773
|
-
|
|
808
|
+
error_handler.report_error(AraError(f"No {file_type} file found."))
|
|
774
809
|
return
|
|
775
810
|
|
|
776
811
|
file_path = self.choose_file_to_load(matching_files, pattern)
|
|
@@ -787,10 +822,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
787
822
|
from ara_cli.ara_config import ConfigManager
|
|
788
823
|
from ara_cli.directory_navigator import DirectoryNavigator
|
|
789
824
|
|
|
790
|
-
plurals = {
|
|
791
|
-
"commands": "commands",
|
|
792
|
-
"rules": "rules"
|
|
793
|
-
}
|
|
825
|
+
plurals = {"commands": "commands", "rules": "rules"}
|
|
794
826
|
|
|
795
827
|
plural = f"{template_type}s"
|
|
796
828
|
if template_type in plurals:
|
|
@@ -798,7 +830,9 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
798
830
|
|
|
799
831
|
if template_name.startswith("global/"):
|
|
800
832
|
directory = f"{TemplatePathManager.get_template_base_path()}/prompt-modules/{plural}/"
|
|
801
|
-
self._load_helper(
|
|
833
|
+
self._load_helper(
|
|
834
|
+
directory, template_name.removeprefix("global/"), template_type
|
|
835
|
+
)
|
|
802
836
|
return
|
|
803
837
|
|
|
804
838
|
ara_config = ConfigManager.get_config()
|
|
@@ -812,7 +846,9 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
812
846
|
os.chdir(original_directory)
|
|
813
847
|
|
|
814
848
|
custom_prompt_templates_subdir = self.config.custom_prompt_templates_subdir
|
|
815
|
-
template_directory =
|
|
849
|
+
template_directory = (
|
|
850
|
+
f"{local_templates_path}/{custom_prompt_templates_subdir}/{plural}"
|
|
851
|
+
)
|
|
816
852
|
self._load_helper(template_directory, template_name, template_type)
|
|
817
853
|
|
|
818
854
|
def _load_template_helper(self, template_name, template_type, default_pattern):
|
|
@@ -820,7 +856,9 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
820
856
|
self._load_helper("prompt.data", default_pattern, template_type)
|
|
821
857
|
return
|
|
822
858
|
|
|
823
|
-
self._load_template_from_global_or_local(
|
|
859
|
+
self._load_template_from_global_or_local(
|
|
860
|
+
template_name=template_name, template_type=template_type
|
|
861
|
+
)
|
|
824
862
|
|
|
825
863
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
826
864
|
@cmd2.with_argparser(extract_parser)
|
|
@@ -832,7 +870,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
832
870
|
file_name=self.chat_name,
|
|
833
871
|
force=args.force,
|
|
834
872
|
write=args.write,
|
|
835
|
-
output=self.poutput
|
|
873
|
+
output=self.poutput,
|
|
836
874
|
)
|
|
837
875
|
command.execute()
|
|
838
876
|
|
|
@@ -860,13 +898,18 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
860
898
|
if path:
|
|
861
899
|
return [path]
|
|
862
900
|
relative_path_for_error = os.path.join(base_directory, file_name)
|
|
863
|
-
|
|
901
|
+
error_handler.report_error(
|
|
902
|
+
AraError,
|
|
903
|
+
f"No givens file found at {relative_path_for_error} or {file_name}",
|
|
904
|
+
)
|
|
864
905
|
return []
|
|
865
906
|
|
|
866
907
|
# If no file_name, check for defaults
|
|
867
908
|
default_files_to_check = [
|
|
868
909
|
os.path.join(base_directory, "prompt.data", "config.prompt_givens.md"),
|
|
869
|
-
os.path.join(
|
|
910
|
+
os.path.join(
|
|
911
|
+
base_directory, "prompt.data", "config.prompt_global_givens.md"
|
|
912
|
+
),
|
|
870
913
|
]
|
|
871
914
|
existing_defaults = [f for f in default_files_to_check if os.path.exists(f)]
|
|
872
915
|
if existing_defaults:
|
|
@@ -877,11 +920,13 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
877
920
|
if not user_input:
|
|
878
921
|
self.poutput("Aborting.")
|
|
879
922
|
return []
|
|
880
|
-
|
|
923
|
+
|
|
881
924
|
path = resolve_path(user_input)
|
|
882
925
|
if path:
|
|
883
926
|
return [path]
|
|
884
|
-
|
|
927
|
+
error_handler.report_error(
|
|
928
|
+
AraError(f"No givens file found at {user_input}. Aborting.")
|
|
929
|
+
)
|
|
885
930
|
return []
|
|
886
931
|
|
|
887
932
|
@cmd2.with_category(CATEGORY_CHAT_CONTROL)
|
|
@@ -891,7 +936,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
891
936
|
|
|
892
937
|
givens_files_to_process = self._find_givens_files(file_name)
|
|
893
938
|
if not givens_files_to_process:
|
|
894
|
-
|
|
939
|
+
error_handler.report_error(AraError("No givens files to load."))
|
|
895
940
|
return
|
|
896
941
|
|
|
897
942
|
for givens_path in givens_files_to_process:
|
|
@@ -899,7 +944,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
899
944
|
# from the markdown file. No directory change is needed.
|
|
900
945
|
content, _ = load_givens(givens_path)
|
|
901
946
|
|
|
902
|
-
with open(self.chat_name,
|
|
947
|
+
with open(self.chat_name, "a", encoding="utf-8") as chat_file:
|
|
903
948
|
chat_file.write(content)
|
|
904
949
|
|
|
905
950
|
self.poutput(f"Loaded files listed and marked in {givens_path}")
|
|
@@ -916,12 +961,15 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
916
961
|
"""Load artefact template"""
|
|
917
962
|
from ara_cli.artefact_models.artefact_templates import template_artefact_of_type
|
|
918
963
|
|
|
919
|
-
artefact = template_artefact_of_type(
|
|
964
|
+
artefact = template_artefact_of_type("".join(template_name))
|
|
920
965
|
if not artefact:
|
|
921
|
-
|
|
966
|
+
error_handler.report_error(
|
|
967
|
+
ValueError(f"No template for '{template_name}' found.")
|
|
968
|
+
)
|
|
969
|
+
return
|
|
922
970
|
write_content = artefact.serialize()
|
|
923
971
|
self.add_prompt_tag_if_needed(self.chat_name)
|
|
924
|
-
with open(self.chat_name,
|
|
972
|
+
with open(self.chat_name, "a", encoding="utf-8") as chat_file:
|
|
925
973
|
chat_file.write(write_content)
|
|
926
974
|
print(f"Loaded {template_name} artefact template")
|
|
927
975
|
|
|
@@ -935,11 +983,12 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
935
983
|
if not text:
|
|
936
984
|
completions = classifiers
|
|
937
985
|
else:
|
|
938
|
-
completions = [
|
|
986
|
+
completions = [
|
|
987
|
+
classifier for classifier in classifiers if classifier.startswith(text)
|
|
988
|
+
]
|
|
939
989
|
|
|
940
990
|
return completions
|
|
941
991
|
|
|
942
|
-
|
|
943
992
|
def _get_plural_template_type(self, template_type: str) -> str:
|
|
944
993
|
"""Determines the plural form of a template type."""
|
|
945
994
|
plurals = {"commands": "commands", "rules": "rules"}
|
|
@@ -952,22 +1001,25 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
952
1001
|
"""
|
|
953
1002
|
current_dir = os.path.dirname(self.chat_name)
|
|
954
1003
|
while True:
|
|
955
|
-
if os.path.isdir(os.path.join(current_dir,
|
|
1004
|
+
if os.path.isdir(os.path.join(current_dir, "ara")):
|
|
956
1005
|
return current_dir
|
|
957
1006
|
parent_dir = os.path.dirname(current_dir)
|
|
958
1007
|
if parent_dir == current_dir: # Reached the filesystem root
|
|
959
1008
|
return None
|
|
960
1009
|
current_dir = parent_dir
|
|
961
1010
|
|
|
962
|
-
def _gather_templates_from_path(
|
|
1011
|
+
def _gather_templates_from_path(
|
|
1012
|
+
self, search_path: str, templates_set: set, prefix: str = ""
|
|
1013
|
+
):
|
|
963
1014
|
"""
|
|
964
1015
|
Scans a given path for items and adds them to the provided set,
|
|
965
1016
|
optionally prepending a prefix.
|
|
966
1017
|
"""
|
|
967
1018
|
import glob
|
|
1019
|
+
|
|
968
1020
|
if not os.path.isdir(search_path):
|
|
969
1021
|
return
|
|
970
|
-
for path in glob.glob(os.path.join(search_path,
|
|
1022
|
+
for path in glob.glob(os.path.join(search_path, "*")):
|
|
971
1023
|
templates_set.add(f"{prefix}{os.path.basename(path)}")
|
|
972
1024
|
|
|
973
1025
|
def _get_available_templates(self, template_type: str) -> list[str]:
|
|
@@ -991,8 +1043,12 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
991
1043
|
# 1. Find Global Templates
|
|
992
1044
|
try:
|
|
993
1045
|
global_base_path = TemplatePathManager.get_template_base_path()
|
|
994
|
-
global_template_dir = os.path.join(
|
|
995
|
-
|
|
1046
|
+
global_template_dir = os.path.join(
|
|
1047
|
+
global_base_path, "prompt-modules", plural_type
|
|
1048
|
+
)
|
|
1049
|
+
self._gather_templates_from_path(
|
|
1050
|
+
global_template_dir, templates, prefix="global/"
|
|
1051
|
+
)
|
|
996
1052
|
except Exception:
|
|
997
1053
|
pass # Silently ignore if global templates are not found
|
|
998
1054
|
|
|
@@ -1000,8 +1056,14 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
1000
1056
|
try:
|
|
1001
1057
|
project_root = self._find_project_root()
|
|
1002
1058
|
if project_root:
|
|
1003
|
-
local_templates_base = os.path.join(
|
|
1004
|
-
|
|
1059
|
+
local_templates_base = os.path.join(
|
|
1060
|
+
project_root, self.config.local_prompt_templates_dir
|
|
1061
|
+
)
|
|
1062
|
+
custom_dir = os.path.join(
|
|
1063
|
+
local_templates_base,
|
|
1064
|
+
self.config.custom_prompt_templates_subdir,
|
|
1065
|
+
plural_type,
|
|
1066
|
+
)
|
|
1005
1067
|
self._gather_templates_from_path(custom_dir, templates)
|
|
1006
1068
|
except Exception:
|
|
1007
1069
|
pass # Silently ignore if local templates cannot be resolved
|
|
@@ -1010,7 +1072,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
1010
1072
|
|
|
1011
1073
|
def _template_completer(self, text: str, template_type: str) -> list[str]:
|
|
1012
1074
|
"""Generic completer for different template types."""
|
|
1013
|
-
available_templates = self.
|
|
1075
|
+
available_templates = self.template_loader.get_available_templates(template_type, os.path.dirname(self.chat_name))
|
|
1014
1076
|
if not text:
|
|
1015
1077
|
return available_templates
|
|
1016
1078
|
return [t for t in available_templates if t.startswith(text)]
|
|
@@ -1029,4 +1091,4 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
|
|
|
1029
1091
|
|
|
1030
1092
|
def complete_LOAD_BLUEPRINT(self, text, line, begidx, endidx):
|
|
1031
1093
|
"""Completer for the LOAD_BLUEPRINT command."""
|
|
1032
|
-
return self._template_completer(text, "blueprint")
|
|
1094
|
+
return self._template_completer(text, "blueprint")
|