ara-cli 0.1.9.62__py3-none-any.whl → 0.1.9.64__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/ara_command_action.py +16 -2
- ara_cli/ara_command_parser.py +2 -0
- ara_cli/artefact_autofix.py +19 -8
- ara_cli/artefact_fuzzy_search.py +21 -2
- ara_cli/artefact_models/artefact_model.py +1 -1
- ara_cli/artefact_models/businessgoal_artefact_model.py +6 -1
- ara_cli/artefact_models/epic_artefact_model.py +6 -1
- ara_cli/artefact_models/feature_artefact_model.py +72 -4
- ara_cli/artefact_models/keyfeature_artefact_model.py +6 -1
- ara_cli/artefact_models/serialize_helper.py +18 -0
- ara_cli/artefact_models/userstory_artefact_model.py +6 -1
- ara_cli/artefact_scan.py +2 -0
- ara_cli/prompt_extractor.py +7 -3
- ara_cli/prompt_handler.py +20 -7
- ara_cli/tag_extractor.py +31 -6
- ara_cli/version.py +1 -1
- {ara_cli-0.1.9.62.dist-info → ara_cli-0.1.9.64.dist-info}/METADATA +1 -1
- {ara_cli-0.1.9.62.dist-info → ara_cli-0.1.9.64.dist-info}/RECORD +21 -20
- {ara_cli-0.1.9.62.dist-info → ara_cli-0.1.9.64.dist-info}/WHEEL +0 -0
- {ara_cli-0.1.9.62.dist-info → ara_cli-0.1.9.64.dist-info}/entry_points.txt +0 -0
- {ara_cli-0.1.9.62.dist-info → ara_cli-0.1.9.64.dist-info}/top_level.txt +0 -0
ara_cli/ara_command_action.py
CHANGED
|
@@ -128,7 +128,10 @@ def list_tags_action(args):
|
|
|
128
128
|
tag_classifier = args.include_classifier
|
|
129
129
|
|
|
130
130
|
tag_extractor = TagExtractor()
|
|
131
|
-
tags = tag_extractor.extract_tags(
|
|
131
|
+
tags = tag_extractor.extract_tags(
|
|
132
|
+
include_classifier=tag_classifier,
|
|
133
|
+
filtered_extra_column=getattr(args, "filtered_extra_column", False)
|
|
134
|
+
)
|
|
132
135
|
|
|
133
136
|
if args.json:
|
|
134
137
|
output = json.dumps({"tags": tags})
|
|
@@ -331,11 +334,15 @@ def reconnect_action(args):
|
|
|
331
334
|
from ara_cli.artefact_models.artefact_load import artefact_from_content
|
|
332
335
|
from ara_cli.artefact_models.artefact_model import Contribution
|
|
333
336
|
from ara_cli.artefact_reader import ArtefactReader
|
|
337
|
+
from ara_cli.artefact_fuzzy_search import find_closest_rule
|
|
334
338
|
|
|
335
339
|
classifier = args.classifier
|
|
336
340
|
artefact_name = args.parameter
|
|
337
341
|
parent_classifier = args.parent_classifier
|
|
338
342
|
parent_name = args.parent_name
|
|
343
|
+
rule = None
|
|
344
|
+
if args.rule:
|
|
345
|
+
rule = ' '.join(args.rule)
|
|
339
346
|
|
|
340
347
|
read_error_message = f"Could not connect {classifier} '{artefact_name}' to {parent_classifier} '{parent_name}'"
|
|
341
348
|
|
|
@@ -364,10 +371,17 @@ def reconnect_action(args):
|
|
|
364
371
|
content=parent_content
|
|
365
372
|
)
|
|
366
373
|
|
|
367
|
-
|
|
374
|
+
contribution = Contribution(
|
|
368
375
|
artefact_name=parent.title,
|
|
369
376
|
classifier=parent.artefact_type
|
|
370
377
|
)
|
|
378
|
+
|
|
379
|
+
if rule:
|
|
380
|
+
closest_rule = find_closest_rule(parent, rule)
|
|
381
|
+
print("")
|
|
382
|
+
contribution.rule = closest_rule
|
|
383
|
+
|
|
384
|
+
artefact.contribution = contribution
|
|
371
385
|
with open(artefact.file_path, 'w') as file:
|
|
372
386
|
artefact_content = artefact.serialize()
|
|
373
387
|
file.write(artefact_content)
|
ara_cli/ara_command_parser.py
CHANGED
|
@@ -121,6 +121,7 @@ def list_tags_parser(subparsers):
|
|
|
121
121
|
tags_parser = subparsers.add_parser("list-tags", help="Show tags")
|
|
122
122
|
tags_parser.add_argument("--json", "-j", help="Output tags as JSON", action=argparse.BooleanOptionalAction)
|
|
123
123
|
tags_parser.add_argument("--include-classifier", choices=classifiers, help="Show tags for an artefact type")
|
|
124
|
+
tags_parser.add_argument("--filtered-extra-column", action="store_true", help="Filter tags for extra column")
|
|
124
125
|
|
|
125
126
|
|
|
126
127
|
def add_chat_arguments(chat_parser):
|
|
@@ -183,6 +184,7 @@ def reconnect_parser(subparsers):
|
|
|
183
184
|
reconnect_parser.add_argument("parameter", help="Filename of artefact").completer = ArtefactCompleter()
|
|
184
185
|
reconnect_parser.add_argument("parent_classifier", choices=classifiers, help="Classifier of the parent artefact type")
|
|
185
186
|
reconnect_parser.add_argument("parent_name", help="Filename of parent artefact").completer = ParentNameCompleter()
|
|
187
|
+
reconnect_parser.add_argument("-r", "--rule", dest="rule", nargs='+')
|
|
186
188
|
|
|
187
189
|
|
|
188
190
|
def read_status_parser(subparsers):
|
ara_cli/artefact_autofix.py
CHANGED
|
@@ -83,26 +83,37 @@ def construct_prompt(artefact_type, reason, file_path, artefact_text):
|
|
|
83
83
|
|
|
84
84
|
prompt = (
|
|
85
85
|
f"Correct the following {artefact_type} artefact to fix the issue: {reason}. "
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
"Provide the corrected artefact. Do not reformulate the artefact, "
|
|
87
|
+
"just fix the pydantic model errors, use correct grammar. "
|
|
88
|
+
"You should follow the name of the file "
|
|
89
|
+
f"from its path {file_path} for naming the arteafact's title. "
|
|
90
|
+
"You are not allowed to use file extention in the artefact title. "
|
|
91
|
+
"You are not allowed to modify, delete or add tags. "
|
|
92
|
+
"User tag should be '@user_<username>'. The pydantic model already provides the '@user_' prefix. "
|
|
93
|
+
"So you should be careful to not make it @user_user_<username>. "
|
|
89
94
|
)
|
|
90
95
|
|
|
91
96
|
if artefact_type == ArtefactType.task:
|
|
92
97
|
prompt += (
|
|
93
|
-
"
|
|
98
|
+
"For task artefacts, if the action items looks like template or empty "
|
|
94
99
|
"then just delete those action items."
|
|
95
|
-
"\nFor user tag it should be '@user_{username}'. So you should be careful to "
|
|
96
|
-
"not make it @user_user_{username}"
|
|
97
100
|
)
|
|
98
101
|
|
|
102
|
+
prompt += (
|
|
103
|
+
"\nThe current artefact is:\n"
|
|
104
|
+
"```\n"
|
|
105
|
+
f"{artefact_text}\n"
|
|
106
|
+
"```"
|
|
107
|
+
)
|
|
108
|
+
|
|
99
109
|
return prompt
|
|
100
110
|
|
|
101
111
|
|
|
102
112
|
def run_agent(prompt, artefact_class):
|
|
103
113
|
from pydantic_ai import Agent
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
# gpt-4o
|
|
115
|
+
# anthropic:claude-3-7-sonnet-20250219
|
|
116
|
+
agent = Agent(model="anthropic:claude-3-7-sonnet-20250219",
|
|
106
117
|
result_type=artefact_class, instrument=True)
|
|
107
118
|
result = agent.run_sync(prompt)
|
|
108
119
|
return result.data
|
ara_cli/artefact_fuzzy_search.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import difflib
|
|
2
|
+
from textwrap import indent
|
|
2
3
|
from typing import Optional
|
|
3
4
|
|
|
4
5
|
|
|
5
|
-
def suggest_close_names(artefact_name: str, all_artefact_names: list[str], message: str):
|
|
6
|
-
closest_matches = difflib.get_close_matches(artefact_name, all_artefact_names, cutoff=
|
|
6
|
+
def suggest_close_names(artefact_name: str, all_artefact_names: list[str], message: str, cutoff=0.5):
|
|
7
|
+
closest_matches = difflib.get_close_matches(artefact_name, all_artefact_names, cutoff=cutoff)
|
|
7
8
|
print(message)
|
|
8
9
|
if not closest_matches:
|
|
9
10
|
return
|
|
@@ -38,3 +39,21 @@ def find_closest_name_match(artefact_name: str, all_artefact_names: list[str]) -
|
|
|
38
39
|
return None
|
|
39
40
|
closest_match = closest_matches[0]
|
|
40
41
|
return closest_match
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def find_closest_rule(parent_artefact, rule):
|
|
45
|
+
parent_classifier = parent_artefact.artefact_type.value
|
|
46
|
+
parent_title = parent_artefact.title
|
|
47
|
+
if not hasattr(parent_artefact, 'rules'):
|
|
48
|
+
raise TypeError(f"{parent_classifier.capitalize()} artefact '{parent_title}' can not possess rules. Only userstories and epics have rules.")
|
|
49
|
+
rules = parent_artefact.rules
|
|
50
|
+
if rule in rules:
|
|
51
|
+
return rule
|
|
52
|
+
print(f"Rule '{rule}' does not match existing rules in {parent_classifier} artefact '{parent_title}'. Attempting to find closest match among existing rules.")
|
|
53
|
+
closest_matches = difflib.get_close_matches(rule, rules, cutoff=0.5)
|
|
54
|
+
rules_list_string = indent('\n'.join(rules), prefix='\t- ')
|
|
55
|
+
if not closest_matches:
|
|
56
|
+
raise ValueError(f"Can not determine a match for rule '{rule}' in {parent_classifier} artefact '{parent_title}'. Found rules:\n{rules_list_string}")
|
|
57
|
+
closest_match = closest_matches[0]
|
|
58
|
+
print(f"Found closest matching rule of '{closest_match}'")
|
|
59
|
+
return closest_match
|
|
@@ -179,7 +179,7 @@ class Artefact(BaseModel, ABC):
|
|
|
179
179
|
)
|
|
180
180
|
description: Optional[str] = Field(
|
|
181
181
|
default=None,
|
|
182
|
-
description="Optional further description to understand the artefact.
|
|
182
|
+
description="Optional further description to understand the artefact. The description should summerize the core intention of the artefact and give additional valuable information about the artefact."
|
|
183
183
|
)
|
|
184
184
|
|
|
185
185
|
@property
|
|
@@ -33,9 +33,14 @@ class BusinessgoalIntent(Intent):
|
|
|
33
33
|
return v
|
|
34
34
|
|
|
35
35
|
def serialize(self):
|
|
36
|
+
from ara_cli.artefact_models.serialize_helper import as_a_serializer
|
|
37
|
+
|
|
36
38
|
lines = []
|
|
39
|
+
|
|
40
|
+
as_a_line = as_a_serializer(self.as_a)
|
|
41
|
+
|
|
37
42
|
lines.append(f"In order to {self.in_order_to}")
|
|
38
|
-
lines.append(
|
|
43
|
+
lines.append(as_a_line)
|
|
39
44
|
lines.append(f"I want {self.i_want}")
|
|
40
45
|
|
|
41
46
|
return "\n".join(lines)
|
|
@@ -34,9 +34,14 @@ class EpicIntent(Intent):
|
|
|
34
34
|
return v
|
|
35
35
|
|
|
36
36
|
def serialize(self):
|
|
37
|
+
from ara_cli.artefact_models.serialize_helper import as_a_serializer
|
|
38
|
+
|
|
37
39
|
lines = []
|
|
40
|
+
|
|
41
|
+
as_a_line = as_a_serializer(self.as_a)
|
|
42
|
+
|
|
38
43
|
lines.append(f"In order to {self.in_order_to}")
|
|
39
|
-
lines.append(
|
|
44
|
+
lines.append(as_a_line)
|
|
40
45
|
lines.append(f"I want {self.i_want}")
|
|
41
46
|
|
|
42
47
|
return "\n".join(lines)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pydantic import BaseModel, field_validator, model_validator, Field
|
|
2
|
-
from typing import List, Dict, Tuple, Union
|
|
2
|
+
from typing import List, Dict, Tuple, Union, Optional
|
|
3
3
|
from ara_cli.artefact_models.artefact_model import Artefact, ArtefactType, Intent
|
|
4
4
|
import re
|
|
5
5
|
|
|
@@ -34,8 +34,13 @@ class FeatureIntent(Intent):
|
|
|
34
34
|
return v
|
|
35
35
|
|
|
36
36
|
def serialize(self):
|
|
37
|
+
from ara_cli.artefact_models.serialize_helper import as_a_serializer
|
|
38
|
+
|
|
37
39
|
lines = []
|
|
38
|
-
|
|
40
|
+
|
|
41
|
+
as_a_line = as_a_serializer(self.as_a)
|
|
42
|
+
|
|
43
|
+
lines.append(as_a_line)
|
|
39
44
|
lines.append(f"I want to {self.i_want_to}")
|
|
40
45
|
lines.append(f"So that {self.so_that}")
|
|
41
46
|
|
|
@@ -59,9 +64,9 @@ class FeatureIntent(Intent):
|
|
|
59
64
|
as_a = line[len(as_a_prefix):].strip()
|
|
60
65
|
if line.startswith(as_a_prefix_alt) and not as_a:
|
|
61
66
|
as_a = line[len(as_a_prefix_alt):].strip()
|
|
62
|
-
|
|
67
|
+
if line.startswith(i_want_to_prefix) and not i_want_to:
|
|
63
68
|
i_want_to = line[len(i_want_to_prefix):].strip()
|
|
64
|
-
|
|
69
|
+
if line.startswith(so_that_prefix) and not so_that:
|
|
65
70
|
so_that = line[len(so_that_prefix):].strip()
|
|
66
71
|
index += 1
|
|
67
72
|
|
|
@@ -93,6 +98,35 @@ class Example(BaseModel):
|
|
|
93
98
|
return cls(values=values)
|
|
94
99
|
|
|
95
100
|
|
|
101
|
+
class Background(BaseModel):
|
|
102
|
+
steps: List[str] = Field(
|
|
103
|
+
description="A list of Gherkin 'Given' type steps that describe what the background does."
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
@field_validator('steps', mode='before')
|
|
107
|
+
def validate_steps(cls, v: List[str]) -> List[str]:
|
|
108
|
+
"""Ensure steps are non-empty and stripped."""
|
|
109
|
+
steps = [step.strip() for step in v if step.strip()]
|
|
110
|
+
if not steps:
|
|
111
|
+
raise ValueError("steps list must not be empty")
|
|
112
|
+
return steps
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def from_lines(cls, lines: List[str], start_idx: int) -> Tuple['Background', int]:
|
|
116
|
+
"""Parse a Background from a list of lines starting at start_idx."""
|
|
117
|
+
if not lines[start_idx].startswith('Background:'):
|
|
118
|
+
raise ValueError("Expected 'Background:' at start index")
|
|
119
|
+
|
|
120
|
+
steps = []
|
|
121
|
+
idx = start_idx + 1
|
|
122
|
+
while idx < len(lines) and not lines[idx].startswith('Background:'):
|
|
123
|
+
step = lines[idx].strip()
|
|
124
|
+
if step:
|
|
125
|
+
steps.append(step)
|
|
126
|
+
idx += 1
|
|
127
|
+
return cls(steps=steps), idx
|
|
128
|
+
|
|
129
|
+
|
|
96
130
|
class Scenario(BaseModel):
|
|
97
131
|
title: str = Field(
|
|
98
132
|
description="The name of the scenario, giving a short summary of the test case. It comes from the 'Scenario:' line in the feature file."
|
|
@@ -208,6 +242,8 @@ class FeatureArtefact(Artefact):
|
|
|
208
242
|
artefact_type: ArtefactType = ArtefactType.feature
|
|
209
243
|
intent: FeatureIntent
|
|
210
244
|
scenarios: List[Union[Scenario, ScenarioOutline]] = Field(default=None)
|
|
245
|
+
background: Optional[Background] = Field(
|
|
246
|
+
default=None, description="Highly optional background Gherkin steps for Feature Artefacts. This steps apply for all scenarios and scenario outlines in this feature file.")
|
|
211
247
|
|
|
212
248
|
@field_validator('artefact_type')
|
|
213
249
|
def validate_artefact_type(cls, v):
|
|
@@ -224,6 +260,16 @@ class FeatureArtefact(Artefact):
|
|
|
224
260
|
def _artefact_type(cls) -> ArtefactType:
|
|
225
261
|
return ArtefactType.feature
|
|
226
262
|
|
|
263
|
+
def _serialize_background(self) -> str:
|
|
264
|
+
"""Helper method to dispatch background serialization."""
|
|
265
|
+
if not self.background:
|
|
266
|
+
return ""
|
|
267
|
+
lines = []
|
|
268
|
+
lines.append(" Background:")
|
|
269
|
+
for step in self.background.steps:
|
|
270
|
+
lines.append(f" {step}")
|
|
271
|
+
return "\n".join(lines)
|
|
272
|
+
|
|
227
273
|
def _serialize_scenario(self, scenario: Union[Scenario, ScenarioOutline]) -> str:
|
|
228
274
|
"""Helper method to dispatch scenario serialization."""
|
|
229
275
|
if isinstance(scenario, Scenario):
|
|
@@ -304,6 +350,10 @@ class FeatureArtefact(Artefact):
|
|
|
304
350
|
lines.append(description)
|
|
305
351
|
lines.append("")
|
|
306
352
|
|
|
353
|
+
if self.background:
|
|
354
|
+
lines.append(self._serialize_background())
|
|
355
|
+
lines.append("")
|
|
356
|
+
|
|
307
357
|
if self.scenarios:
|
|
308
358
|
for scenario in self.scenarios:
|
|
309
359
|
lines.append(self._serialize_scenario(scenario))
|
|
@@ -316,9 +366,11 @@ class FeatureArtefact(Artefact):
|
|
|
316
366
|
fields = super()._parse_common_fields(text)
|
|
317
367
|
|
|
318
368
|
intent = FeatureIntent.deserialize(text)
|
|
369
|
+
background = cls.deserialize_background(text)
|
|
319
370
|
scenarios = cls.deserialize_scenarios(text)
|
|
320
371
|
|
|
321
372
|
fields['scenarios'] = scenarios
|
|
373
|
+
fields['background'] = background
|
|
322
374
|
fields['intent'] = intent
|
|
323
375
|
|
|
324
376
|
return cls(**fields)
|
|
@@ -343,3 +395,19 @@ class FeatureArtefact(Artefact):
|
|
|
343
395
|
else:
|
|
344
396
|
idx += 1
|
|
345
397
|
return scenarios
|
|
398
|
+
|
|
399
|
+
@classmethod
|
|
400
|
+
def deserialize_background(cls, text):
|
|
401
|
+
lines = [line.strip()
|
|
402
|
+
for line in text.strip().splitlines() if line.strip()]
|
|
403
|
+
|
|
404
|
+
background = None
|
|
405
|
+
idx = 0
|
|
406
|
+
while idx < len(lines):
|
|
407
|
+
line = lines[idx].strip()
|
|
408
|
+
if line.startswith('Background:'):
|
|
409
|
+
background, next_idx = Background.from_lines(lines, idx)
|
|
410
|
+
break
|
|
411
|
+
else:
|
|
412
|
+
idx += 1
|
|
413
|
+
return background
|
|
@@ -33,9 +33,14 @@ class KeyfeatureIntent(Intent):
|
|
|
33
33
|
return v
|
|
34
34
|
|
|
35
35
|
def serialize(self):
|
|
36
|
+
from ara_cli.artefact_models.serialize_helper import as_a_serializer
|
|
37
|
+
|
|
36
38
|
lines = []
|
|
39
|
+
|
|
40
|
+
as_a_line = as_a_serializer(self.as_a)
|
|
41
|
+
|
|
37
42
|
lines.append(f"In order to {self.in_order_to}")
|
|
38
|
-
lines.append(
|
|
43
|
+
lines.append(as_a_line)
|
|
39
44
|
lines.append(f"I want {self.i_want}")
|
|
40
45
|
|
|
41
46
|
return "\n".join(lines)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
def as_a_serializer(as_a):
|
|
2
|
+
role = as_a.strip()
|
|
3
|
+
|
|
4
|
+
exceptions_for_a = ('user', 'university', 'one-time', 'european', 'unit')
|
|
5
|
+
exceptions_for_an = ('hour', 'honest', 'heir')
|
|
6
|
+
role_lower = role.lower()
|
|
7
|
+
as_a_prefix = ""
|
|
8
|
+
|
|
9
|
+
if any(role_lower.startswith(e) for e in exceptions_for_a):
|
|
10
|
+
as_a_prefix = "As a"
|
|
11
|
+
elif any(role_lower.startswith(e) for e in exceptions_for_an):
|
|
12
|
+
as_a_prefix = "As an"
|
|
13
|
+
elif role_lower.startswith(('a', 'e', 'i', 'o', 'u')):
|
|
14
|
+
as_a_prefix = "As an"
|
|
15
|
+
else:
|
|
16
|
+
as_a_prefix = "As a"
|
|
17
|
+
|
|
18
|
+
return f"{as_a_prefix} {role}"
|
|
@@ -33,9 +33,14 @@ class UserstoryIntent(Intent):
|
|
|
33
33
|
return v
|
|
34
34
|
|
|
35
35
|
def serialize(self):
|
|
36
|
+
from ara_cli.artefact_models.serialize_helper import as_a_serializer
|
|
37
|
+
|
|
36
38
|
lines = []
|
|
39
|
+
|
|
40
|
+
as_a_line = as_a_serializer(self.as_a)
|
|
41
|
+
|
|
37
42
|
lines.append(f"In order to {self.in_order_to}")
|
|
38
|
-
lines.append(
|
|
43
|
+
lines.append(as_a_line)
|
|
39
44
|
lines.append(f"I want {self.i_want}")
|
|
40
45
|
|
|
41
46
|
return "\n".join(lines)
|
ara_cli/artefact_scan.py
CHANGED
|
@@ -25,6 +25,8 @@ def find_invalid_files(classified_artefact_info, classifier):
|
|
|
25
25
|
for artefact_info in classified_artefact_info[classifier]:
|
|
26
26
|
if "templates/" in artefact_info["file_path"]:
|
|
27
27
|
continue
|
|
28
|
+
if ".data" in artefact_info["file_path"]:
|
|
29
|
+
continue
|
|
28
30
|
is_valid, reason = check_file(artefact_info["file_path"], artefact_class)
|
|
29
31
|
if not is_valid:
|
|
30
32
|
invalid_files.append((artefact_info["file_path"], reason))
|
ara_cli/prompt_extractor.py
CHANGED
|
@@ -184,10 +184,14 @@ def handle_existing_file(filename, block_content):
|
|
|
184
184
|
create_file_if_not_exist(filename, block_content)
|
|
185
185
|
else:
|
|
186
186
|
print(f"File {filename} exists, creating modification prompt")
|
|
187
|
-
|
|
187
|
+
prompt_text = create_prompt_for_file_modification(block_content, filename)
|
|
188
|
+
messages = [{"role": "user", "content": prompt_text}]
|
|
188
189
|
response = ""
|
|
189
|
-
|
|
190
|
-
|
|
190
|
+
|
|
191
|
+
for chunk in send_prompt(messages):
|
|
192
|
+
content = chunk.choices[0].delta.content
|
|
193
|
+
if content:
|
|
194
|
+
response += content
|
|
191
195
|
modify_and_save_file(response, filename)
|
|
192
196
|
|
|
193
197
|
|
ara_cli/prompt_handler.py
CHANGED
|
@@ -355,8 +355,12 @@ def prepend_system_prompt(message_list):
|
|
|
355
355
|
|
|
356
356
|
|
|
357
357
|
def append_images_to_message(message, image_data_list):
|
|
358
|
-
|
|
359
|
-
|
|
358
|
+
if not image_data_list:
|
|
359
|
+
return message
|
|
360
|
+
new_content_list = [{"type": "text", "text": message}]
|
|
361
|
+
new_content_list.extend(image_data_list)
|
|
362
|
+
|
|
363
|
+
message["content"] = new_content_list
|
|
360
364
|
|
|
361
365
|
return message
|
|
362
366
|
|
|
@@ -376,14 +380,23 @@ def create_and_send_custom_prompt(classifier, parameter):
|
|
|
376
380
|
append_headings(classifier, parameter, "prompt")
|
|
377
381
|
write_prompt_result(classifier, parameter, prompt)
|
|
378
382
|
|
|
379
|
-
|
|
380
|
-
|
|
383
|
+
base_message = {
|
|
384
|
+
"role": "user",
|
|
385
|
+
"content": combined_content_markdown
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
final_message = append_images_to_message(base_message, image_data_list)
|
|
381
389
|
|
|
390
|
+
message_list_to_send = [final_message]
|
|
391
|
+
|
|
392
|
+
append_headings(classifier, parameter, "result")
|
|
382
393
|
artefact_data_path = f"ara/{sub_directory}/{parameter}.data/{classifier}.prompt_log.md"
|
|
383
394
|
with open(artefact_data_path, 'a') as file:
|
|
384
|
-
for chunk in send_prompt(
|
|
385
|
-
|
|
386
|
-
|
|
395
|
+
for chunk in send_prompt(message_list_to_send):
|
|
396
|
+
content = chunk.choices[0].delta.content
|
|
397
|
+
if content:
|
|
398
|
+
file.write(content)
|
|
399
|
+
file.flush()
|
|
387
400
|
# write_prompt_result(classifier, parameter, response)
|
|
388
401
|
|
|
389
402
|
|
ara_cli/tag_extractor.py
CHANGED
|
@@ -6,7 +6,7 @@ class TagExtractor:
|
|
|
6
6
|
def __init__(self, file_system=None):
|
|
7
7
|
self.file_system = file_system or os
|
|
8
8
|
|
|
9
|
-
def extract_tags(self, navigate_to_target=False, include_classifier=None):
|
|
9
|
+
def extract_tags(self, navigate_to_target=False, include_classifier=None, filtered_extra_column=False):
|
|
10
10
|
from ara_cli.template_manager import DirectoryNavigator
|
|
11
11
|
from ara_cli.artefact_reader import ArtefactReader
|
|
12
12
|
|
|
@@ -21,11 +21,36 @@ class TagExtractor:
|
|
|
21
21
|
|
|
22
22
|
unique_tags = set()
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
if filtered_extra_column:
|
|
25
|
+
status_tags = {"to-do", "in-progress", "review", "done", "closed"}
|
|
26
|
+
filtered_artefacts = []
|
|
27
|
+
|
|
28
|
+
for artefact_list in artefacts.values():
|
|
29
|
+
for artefact in artefact_list:
|
|
30
|
+
tags = artefact.tags + \
|
|
31
|
+
[artefact.status] if artefact.status else artefact.tags
|
|
32
|
+
tag_set = set(tag for tag in tags if tag is not None)
|
|
33
|
+
if not tag_set & status_tags:
|
|
34
|
+
filtered_artefacts.append(artefact)
|
|
35
|
+
|
|
36
|
+
for artefact in filtered_artefacts:
|
|
37
|
+
tags = [tag for tag in (
|
|
38
|
+
artefact.tags + [artefact.status]) if tag is not None]
|
|
39
|
+
for tag in tags:
|
|
40
|
+
if (
|
|
41
|
+
tag in status_tags
|
|
42
|
+
or tag.startswith("priority_")
|
|
43
|
+
or tag.startswith("user_")
|
|
44
|
+
):
|
|
45
|
+
continue
|
|
46
|
+
unique_tags.add(tag)
|
|
47
|
+
|
|
48
|
+
else:
|
|
49
|
+
for artefact_list in artefacts.values():
|
|
50
|
+
for artefact in artefact_list:
|
|
51
|
+
user_tags = [f"user_{tag}" for tag in artefact.users]
|
|
52
|
+
tags = [tag for tag in (artefact.tags + [artefact.status] + user_tags) if tag is not None]
|
|
53
|
+
unique_tags.update(tags)
|
|
29
54
|
|
|
30
55
|
sorted_tags = sorted(unique_tags)
|
|
31
56
|
return sorted_tags
|
ara_cli/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# version.py
|
|
2
|
-
__version__ = "0.1.9.
|
|
2
|
+
__version__ = "0.1.9.64" # fith parameter like .0 for local install test purposes only. official numbers should be 4 digit numbers
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
ara_cli/__init__.py,sha256=0zl7IegxTid26EBGLav_fXZ4CCIV3H5TfAoFQiOHjvg,148
|
|
2
2
|
ara_cli/__main__.py,sha256=Z6XYWRLceIoZPvfC-X9EXouSZdtFOOe84kKVWJGA4r4,1861
|
|
3
|
-
ara_cli/ara_command_action.py,sha256=
|
|
4
|
-
ara_cli/ara_command_parser.py,sha256=
|
|
3
|
+
ara_cli/ara_command_action.py,sha256=5Q9dwS4urZCkD52trqTghnYViBLvOBqwcG3oDYBNgHg,20003
|
|
4
|
+
ara_cli/ara_command_parser.py,sha256=iG0IHL3So96viB7_lyetj_wbOeCLlToUpRY9HvBNY8w,17256
|
|
5
5
|
ara_cli/ara_config.py,sha256=_Arkr-b9XnrNHbBlFKb9tAo3OmdP4ZZiWvbY9m6Sbo0,4178
|
|
6
|
-
ara_cli/artefact_autofix.py,sha256=
|
|
6
|
+
ara_cli/artefact_autofix.py,sha256=T0TJ6vBxveMoOKm6c22c6D-iMuBHlCksvNLil_O6xaM,4885
|
|
7
7
|
ara_cli/artefact_creator.py,sha256=mkxKHkVIK2GdmUrKHAjKvhq66eg21S3x_cvK1ZA9DPw,5964
|
|
8
8
|
ara_cli/artefact_deleter.py,sha256=Co4wwCH3yW8H9NrOq7_2p5571EeHr0TsfE-H8KqoOfY,1900
|
|
9
|
-
ara_cli/artefact_fuzzy_search.py,sha256=
|
|
9
|
+
ara_cli/artefact_fuzzy_search.py,sha256=TD96fV5FoyJzLClXiHHlysPruK4t7yAgQ_kPnQqyMRo,2412
|
|
10
10
|
ara_cli/artefact_link_updater.py,sha256=itMS_Z64jE8bBly9WA01z8PqkBeNW6ntTO7ryMeCTRg,3703
|
|
11
11
|
ara_cli/artefact_lister.py,sha256=jhk4n4eqp7hDIq07q43QzS7-36BM3OfZ4EABxCeOGcw,4764
|
|
12
12
|
ara_cli/artefact_reader.py,sha256=qNaMPWShmWtDU5LLdh9efFB27djI4NAoq6zEFwdTd38,6983
|
|
13
13
|
ara_cli/artefact_renamer.py,sha256=loIn1DF9kVnjhH7wP1v5qUvt3s0uKeWXuQPrHXenQGE,4025
|
|
14
|
-
ara_cli/artefact_scan.py,sha256=
|
|
14
|
+
ara_cli/artefact_scan.py,sha256=7PH7TE2B2Py7wGQxl7EYM3r6Fr9kVLAFtNErP0QRoXM,1950
|
|
15
15
|
ara_cli/chat.py,sha256=7xTtPEDk052_wmIzoti7GavEJ1vpRxe5c084WQ1C7dg,28617
|
|
16
16
|
ara_cli/classifier.py,sha256=zWskj7rBYdqYBGjksBm46iTgVU5IIf2PZsJr4qeiwVU,1878
|
|
17
17
|
ara_cli/codefusionretriever.py,sha256=fCHgXdIBRzkVAnapX-KI2NQ44XbrrF4tEQmn5J6clUI,1980
|
|
@@ -24,27 +24,28 @@ ara_cli/filename_validator.py,sha256=Aw9PL8d5-Ymhp3EY6lDrUBk3cudaNqo1Uw5RzPpI1jA
|
|
|
24
24
|
ara_cli/list_filter.py,sha256=Not17hIngI37gZsLtIKxopB-BmyWoOGlBzSqBwh-Zpc,5273
|
|
25
25
|
ara_cli/output_suppressor.py,sha256=ZByUwLH2DxOb-eJ31KQbtIziBKdykoyxvwxZ0tSammA,371
|
|
26
26
|
ara_cli/prompt_chat.py,sha256=kd_OINDQFit6jN04bb7mzgY259JBbRaTaNp9F-webkc,1346
|
|
27
|
-
ara_cli/prompt_extractor.py,sha256=
|
|
28
|
-
ara_cli/prompt_handler.py,sha256=
|
|
27
|
+
ara_cli/prompt_extractor.py,sha256=a8LwPj6U8sG_v3SqDXQyPvDZQds4kHnYSO8eGissYJA,7503
|
|
28
|
+
ara_cli/prompt_handler.py,sha256=1gz2VkK7zl0RAzit1UmxplNNd2Zu6J_7eHocgKiw_hQ,17473
|
|
29
29
|
ara_cli/prompt_rag.py,sha256=vmlt4-rSboWibwgO_KUF79TK99YXT5KXjmbD9FeWdZY,7449
|
|
30
30
|
ara_cli/run_file_lister.py,sha256=XbrrDTJXp1LFGx9Lv91SNsEHZPP-PyEMBF_P4btjbDA,2360
|
|
31
|
-
ara_cli/tag_extractor.py,sha256=
|
|
31
|
+
ara_cli/tag_extractor.py,sha256=IrjX8R8pdas3_qWuDsXXnwCVDD0uUrgqjzfqTD81t3I,2173
|
|
32
32
|
ara_cli/template_manager.py,sha256=YXPj2jGNDb-diIHFEK_vGJ-ZucodnXSGAPofKTnOofI,6633
|
|
33
33
|
ara_cli/update_config_prompt.py,sha256=PZgNIN3dTw6p80GyX8Sp5apkAhSoykwnkEbHo3IOkUo,4571
|
|
34
|
-
ara_cli/version.py,sha256=
|
|
34
|
+
ara_cli/version.py,sha256=rBCA0K3GrvOvnsjnnIVwI8EKzmt0b2Eh7phC0VgDNIM,146
|
|
35
35
|
ara_cli/artefact_models/artefact_load.py,sha256=dNcwZDW2Dk0bts9YnPZ0ESmWD2NbsLIvl4Z-qQeGmTQ,401
|
|
36
36
|
ara_cli/artefact_models/artefact_mapping.py,sha256=8aD0spBjkJ8toMAmFawc6UTUxB6-tEEViZXv2I-r88Q,1874
|
|
37
|
-
ara_cli/artefact_models/artefact_model.py,sha256=
|
|
37
|
+
ara_cli/artefact_models/artefact_model.py,sha256=W_jxafOd7d-1SxvB2G8dKG7_rT5t-EZo1-PnvlPHqso,14915
|
|
38
38
|
ara_cli/artefact_models/artefact_templates.py,sha256=Vd7SwoRVKNGKZmxBKS6f9FE1ThUOCqZLScu0ClPfIu8,8321
|
|
39
|
-
ara_cli/artefact_models/businessgoal_artefact_model.py,sha256=
|
|
39
|
+
ara_cli/artefact_models/businessgoal_artefact_model.py,sha256=jqYFMXjWle0YW9RvcFLDBAwy61bdT5VuDT_6lTOFzMw,4853
|
|
40
40
|
ara_cli/artefact_models/capability_artefact_model.py,sha256=SZqHx4O2mj4urn77Stnj4_Jxtlq3-LgBBU9SMkByppI,3079
|
|
41
|
-
ara_cli/artefact_models/epic_artefact_model.py,sha256=
|
|
41
|
+
ara_cli/artefact_models/epic_artefact_model.py,sha256=IadQWs6SWNcLgwvtOQWmYDyV9xLr3WwAsx-YMFan5fA,5765
|
|
42
42
|
ara_cli/artefact_models/example_artefact_model.py,sha256=UXrKbaPotg1jwcrVSdCeo-XH4tTD_-U1e3giaBn5_xg,1384
|
|
43
|
-
ara_cli/artefact_models/feature_artefact_model.py,sha256=
|
|
43
|
+
ara_cli/artefact_models/feature_artefact_model.py,sha256=BeLsq9ZinzIDwss8nurIbxJZQ2qPgyRKRHrRlrl-zHA,15583
|
|
44
44
|
ara_cli/artefact_models/issue_artefact_model.py,sha256=v6CpKnkqiUh6Wch2kkEmyyW49c8ysdy1qz8l1Ft9uJA,2552
|
|
45
|
-
ara_cli/artefact_models/keyfeature_artefact_model.py,sha256=
|
|
45
|
+
ara_cli/artefact_models/keyfeature_artefact_model.py,sha256=a3MyAiePN9n_GTN6QkTvamdsaorwVUff6w-9CdRZSlo,4243
|
|
46
|
+
ara_cli/artefact_models/serialize_helper.py,sha256=0XCruO70-fyfLfTn7pnt8NrSQe79eYNUAjuQaV8K6_8,586
|
|
46
47
|
ara_cli/artefact_models/task_artefact_model.py,sha256=kHMw_Tr-Ud3EeHWpRWy4jI0xFnPzGZ-FT52c5rSrT1k,3558
|
|
47
|
-
ara_cli/artefact_models/userstory_artefact_model.py,sha256=
|
|
48
|
+
ara_cli/artefact_models/userstory_artefact_model.py,sha256=u6G8wdeE2EpOsg1OPR-s8uShB4A77GfqN0vkSSuthFI,6582
|
|
48
49
|
ara_cli/artefact_models/vision_artefact_model.py,sha256=KcNE3QQjyT29ZMMhCQo4pOcXKTkI6pXLvyfqoN2kuUQ,5920
|
|
49
50
|
ara_cli/templates/agile.artefacts,sha256=nTA8dp98HWKAD-0qhmNpVYIfkVGoJshZqMJGnphiOsE,7932
|
|
50
51
|
ara_cli/templates/template.businessgoal,sha256=3OU-y8dOCRbRsB9ovBzwFPxHSbG0dqbkok0uJnZIOd4,524
|
|
@@ -149,8 +150,8 @@ ara_cli/tests/test_list_filter.py,sha256=gSRKirTtFuhRS3QlFHqWl89WvCvAdVEnFsCWTYm
|
|
|
149
150
|
ara_cli/tests/test_tag_extractor.py,sha256=n2xNApbDciqKO3QuaveEWSPXU1PCUa_EhxlZMrukONw,2074
|
|
150
151
|
ara_cli/tests/test_template_manager.py,sha256=bRxka6cxHsCAOvXjfG8MrVO8qSZXhxW01tnph80UtNk,3143
|
|
151
152
|
ara_cli/tests/test_update_config_prompt.py,sha256=vSsLvc18HZdVjVM93qXWVbJt752xTLL6VGjSVCrPufk,6729
|
|
152
|
-
ara_cli-0.1.9.
|
|
153
|
-
ara_cli-0.1.9.
|
|
154
|
-
ara_cli-0.1.9.
|
|
155
|
-
ara_cli-0.1.9.
|
|
156
|
-
ara_cli-0.1.9.
|
|
153
|
+
ara_cli-0.1.9.64.dist-info/METADATA,sha256=hMa8LLYlDMGNBHL5R7CwM1QamWGbbsMe7hTbajvHQ1I,415
|
|
154
|
+
ara_cli-0.1.9.64.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
155
|
+
ara_cli-0.1.9.64.dist-info/entry_points.txt,sha256=v4h7MzysTgSIDYfEo3oj4Kz_8lzsRa3hq-KJHEcLVX8,45
|
|
156
|
+
ara_cli-0.1.9.64.dist-info/top_level.txt,sha256=zzee_PwFmKqfBi9XgIunP6xy2S4TIt593CLLxenNaAE,8
|
|
157
|
+
ara_cli-0.1.9.64.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|