fabricatio 0.2.8.dev3__cp312-cp312-win_amd64.whl → 0.2.9.dev0__cp312-cp312-win_amd64.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.
Files changed (42) hide show
  1. fabricatio/__init__.py +4 -11
  2. fabricatio/actions/__init__.py +1 -0
  3. fabricatio/actions/article.py +63 -87
  4. fabricatio/actions/article_rag.py +54 -43
  5. fabricatio/actions/rag.py +2 -1
  6. fabricatio/actions/rules.py +39 -0
  7. fabricatio/capabilities/__init__.py +1 -0
  8. fabricatio/capabilities/censor.py +90 -0
  9. fabricatio/capabilities/check.py +127 -29
  10. fabricatio/capabilities/correct.py +143 -100
  11. fabricatio/capabilities/rag.py +5 -4
  12. fabricatio/capabilities/rating.py +65 -16
  13. fabricatio/capabilities/review.py +1 -1
  14. fabricatio/capabilities/task.py +2 -1
  15. fabricatio/config.py +11 -3
  16. fabricatio/models/action.py +14 -7
  17. fabricatio/models/adv_kwargs_types.py +25 -0
  18. fabricatio/models/extra/__init__.py +1 -0
  19. fabricatio/models/extra/advanced_judge.py +5 -2
  20. fabricatio/models/extra/article_base.py +3 -20
  21. fabricatio/models/extra/article_main.py +2 -3
  22. fabricatio/models/extra/patches.py +20 -0
  23. fabricatio/models/extra/problem.py +41 -8
  24. fabricatio/models/extra/rule.py +26 -9
  25. fabricatio/models/generic.py +310 -55
  26. fabricatio/models/kwargs_types.py +23 -17
  27. fabricatio/models/task.py +1 -1
  28. fabricatio/models/tool.py +149 -14
  29. fabricatio/models/usages.py +50 -42
  30. fabricatio/parser.py +7 -8
  31. fabricatio/rust.cp312-win_amd64.pyd +0 -0
  32. fabricatio/{_rust_instances.py → rust_instances.py} +1 -1
  33. fabricatio/workflows/__init__.py +1 -0
  34. fabricatio-0.2.9.dev0.data/scripts/tdown.exe +0 -0
  35. {fabricatio-0.2.8.dev3.dist-info → fabricatio-0.2.9.dev0.dist-info}/METADATA +1 -1
  36. fabricatio-0.2.9.dev0.dist-info/RECORD +61 -0
  37. fabricatio/_rust.cp312-win_amd64.pyd +0 -0
  38. fabricatio-0.2.8.dev3.data/scripts/tdown.exe +0 -0
  39. fabricatio-0.2.8.dev3.dist-info/RECORD +0 -53
  40. /fabricatio/{_rust.pyi → rust.pyi} +0 -0
  41. {fabricatio-0.2.8.dev3.dist-info → fabricatio-0.2.9.dev0.dist-info}/WHEEL +0 -0
  42. {fabricatio-0.2.8.dev3.dist-info → fabricatio-0.2.9.dev0.dist-info}/licenses/LICENSE +0 -0
@@ -4,15 +4,17 @@ from itertools import permutations
4
4
  from random import sample
5
5
  from typing import Dict, List, Optional, Set, Tuple, Union, Unpack, overload
6
6
 
7
- from fabricatio._rust_instances import TEMPLATE_MANAGER
7
+ from more_itertools import flatten, windowed
8
+ from pydantic import NonNegativeInt, PositiveInt
9
+
8
10
  from fabricatio.config import configs
9
11
  from fabricatio.journal import logger
10
- from fabricatio.models.kwargs_types import ValidateKwargs
12
+ from fabricatio.models.generic import Display
13
+ from fabricatio.models.kwargs_types import CompositeScoreKwargs, ValidateKwargs
11
14
  from fabricatio.models.usages import LLMUsage
12
15
  from fabricatio.parser import JsonCapture
13
- from fabricatio.utils import override_kwargs
14
- from more_itertools import flatten, windowed
15
- from pydantic import NonNegativeInt, PositiveInt
16
+ from fabricatio.rust_instances import TEMPLATE_MANAGER
17
+ from fabricatio.utils import ok, override_kwargs
16
18
 
17
19
 
18
20
  class Rating(LLMUsage):
@@ -86,6 +88,7 @@ class Rating(LLMUsage):
86
88
  to_rate: str,
87
89
  topic: str,
88
90
  criteria: Set[str],
91
+ manual: Optional[Dict[str, str]],
89
92
  score_range: Tuple[float, float] = (0.0, 1.0),
90
93
  **kwargs: Unpack[ValidateKwargs],
91
94
  ) -> Dict[str, float]: ...
@@ -96,6 +99,7 @@ class Rating(LLMUsage):
96
99
  to_rate: List[str],
97
100
  topic: str,
98
101
  criteria: Set[str],
102
+ manual: Optional[Dict[str, str]],
99
103
  score_range: Tuple[float, float] = (0.0, 1.0),
100
104
  **kwargs: Unpack[ValidateKwargs],
101
105
  ) -> List[Dict[str, float]]: ...
@@ -105,6 +109,7 @@ class Rating(LLMUsage):
105
109
  to_rate: Union[str, List[str]],
106
110
  topic: str,
107
111
  criteria: Set[str],
112
+ manual: Optional[Dict[str, str]],
108
113
  score_range: Tuple[float, float] = (0.0, 1.0),
109
114
  **kwargs: Unpack[ValidateKwargs],
110
115
  ) -> Optional[Dict[str, float] | List[Dict[str, float]]]:
@@ -114,6 +119,7 @@ class Rating(LLMUsage):
114
119
  to_rate (Union[str, List[str]]): The string or sequence of strings to be rated.
115
120
  topic (str): The topic related to the task.
116
121
  criteria (Set[str]): A set of criteria for rating.
122
+ manual (Optional[Dict[str, str]]): A dictionary containing the rating criteria. If not provided, then this method will draft the criteria automatically.
117
123
  score_range (Tuple[float, float], optional): A tuple representing the valid score range. Defaults to (0.0, 1.0).
118
124
  **kwargs (Unpack[ValidateKwargs]): Additional keyword arguments for the LLM usage.
119
125
 
@@ -121,7 +127,11 @@ class Rating(LLMUsage):
121
127
  Union[Dict[str, float], List[Dict[str, float]]]: A dictionary with the ratings for each criterion if a single string is provided,
122
128
  or a list of dictionaries with the ratings for each criterion if a sequence of strings is provided.
123
129
  """
124
- manual = await self.draft_rating_manual(topic, criteria, **kwargs) or dict(zip(criteria, criteria, strict=True))
130
+ manual = (
131
+ manual
132
+ or await self.draft_rating_manual(topic, criteria, **override_kwargs(kwargs, default=None))
133
+ or dict(zip(criteria, criteria, strict=True))
134
+ )
125
135
 
126
136
  return await self.rate_fine_grind(to_rate, manual, score_range, **kwargs)
127
137
 
@@ -309,7 +319,7 @@ class Rating(LLMUsage):
309
319
  validator=lambda resp: JsonCapture.validate_with(resp, target_type=float),
310
320
  **kwargs,
311
321
  )
312
- weights = [1]
322
+ weights = [1.0]
313
323
  for rw in relative_weights:
314
324
  weights.append(weights[-1] * rw)
315
325
  total = sum(weights)
@@ -319,27 +329,66 @@ class Rating(LLMUsage):
319
329
  self,
320
330
  topic: str,
321
331
  to_rate: List[str],
322
- reasons_count: PositiveInt = 2,
323
- criteria_count: PositiveInt = 5,
324
- **kwargs: Unpack[ValidateKwargs],
332
+ criteria: Optional[Set[str]] = None,
333
+ weights: Optional[Dict[str, float]] = None,
334
+ manual: Optional[Dict[str, str]] = None,
335
+ **kwargs: Unpack[ValidateKwargs[List[Dict[str, float]]]],
325
336
  ) -> List[float]:
326
337
  """Calculates the composite scores for a list of items based on a given topic and criteria.
327
338
 
328
339
  Args:
329
340
  topic (str): The topic for the rating.
330
341
  to_rate (List[str]): A list of strings to be rated.
331
- reasons_count (PositiveInt, optional): The number of reasons to extract from each pair of examples. Defaults to 2.
332
- criteria_count (PositiveInt, optional): The number of criteria to draft. Defaults to 5.
342
+ criteria (Optional[Set[str]]): A set of criteria for the rating. Defaults to None.
343
+ weights (Optional[Dict[str, float]]): A dictionary of rating weights for each criterion. Defaults to None.
344
+ manual (Optional[Dict[str, str]]): A dictionary of manual ratings for each item. Defaults to None.
333
345
  **kwargs (Unpack[ValidateKwargs]): Additional keyword arguments for the LLM usage.
334
346
 
335
347
  Returns:
336
348
  List[float]: A list of composite scores for the items.
337
349
  """
338
- criteria = await self.draft_rating_criteria_from_examples(
339
- topic, to_rate, reasons_count, criteria_count, **kwargs
350
+ criteria = ok(
351
+ criteria
352
+ or await self.draft_rating_criteria_from_examples(topic, to_rate, **override_kwargs(kwargs, default=None))
353
+ )
354
+ weights = ok(
355
+ weights or await self.drafting_rating_weights_klee(topic, criteria, **override_kwargs(kwargs, default=None))
340
356
  )
341
- weights = await self.drafting_rating_weights_klee(topic, criteria, **kwargs)
342
357
  logger.info(f"Criteria: {criteria}\nWeights: {weights}")
343
- ratings_seq = await self.rate(to_rate, topic, criteria, **kwargs)
358
+ ratings_seq = await self.rate(to_rate, topic, criteria, manual, **kwargs)
344
359
 
345
360
  return [sum(ratings[c] * weights[c] for c in criteria) for ratings in ratings_seq]
361
+
362
+ @overload
363
+ async def best(self, candidates: List[str], k: int=1, **kwargs: Unpack[CompositeScoreKwargs]) -> List[str]: ...
364
+ @overload
365
+ async def best[T: Display](
366
+ self, candidates: List[T], k: int=1, **kwargs: Unpack[CompositeScoreKwargs]
367
+ ) -> List[T]: ...
368
+
369
+ async def best[T: Display](
370
+ self, candidates: List[str] | List[T], k: int=1, **kwargs: Unpack[CompositeScoreKwargs]
371
+ ) -> Optional[List[str] | List[T]]:
372
+ """Choose the best candidates from the list of candidates based on the composite score.
373
+
374
+ Args:
375
+ k (int): The number of best candidates to choose.
376
+ candidates (List[str]): A list of candidates to choose from.
377
+ **kwargs (CompositeScoreKwargs): Additional keyword arguments for the composite score calculation.
378
+
379
+ Returns:
380
+ List[str]: The best candidates.
381
+ """
382
+ if (leng := len(candidates)) == 0:
383
+ logger.warning(f"No candidates, got {leng}, return None.")
384
+ return None
385
+
386
+ if leng == 1:
387
+ logger.warning(f"Only one candidate, got {leng}, return it.")
388
+ return candidates
389
+ logger.info(f"Choose best {k} from {leng} candidates.")
390
+
391
+ rating_seq = await self.composite_score(
392
+ to_rate=[c.display() if isinstance(c, Display) else c for c in candidates], **kwargs
393
+ )
394
+ return [a[0] for a in sorted(zip(candidates, rating_seq, strict=True), key=lambda x: x[1], reverse=True)[:k]] # pyright: ignore [reportReturnType]
@@ -2,7 +2,6 @@
2
2
 
3
3
  from typing import Dict, Optional, Set, Unpack
4
4
 
5
- from fabricatio._rust_instances import TEMPLATE_MANAGER
6
5
  from fabricatio.capabilities.propose import Propose
7
6
  from fabricatio.capabilities.rating import Rating
8
7
  from fabricatio.config import configs
@@ -10,6 +9,7 @@ from fabricatio.models.extra.problem import Improvement
10
9
  from fabricatio.models.generic import Display, WithBriefing
11
10
  from fabricatio.models.kwargs_types import ReviewKwargs, ValidateKwargs
12
11
  from fabricatio.models.task import Task
12
+ from fabricatio.rust_instances import TEMPLATE_MANAGER
13
13
  from fabricatio.utils import ok
14
14
 
15
15
 
@@ -4,7 +4,7 @@ from types import CodeType
4
4
  from typing import Any, Dict, List, Optional, Tuple, Unpack
5
5
 
6
6
  import orjson
7
- from fabricatio._rust_instances import TEMPLATE_MANAGER
7
+
8
8
  from fabricatio.capabilities.propose import Propose
9
9
  from fabricatio.config import configs
10
10
  from fabricatio.journal import logger
@@ -13,6 +13,7 @@ from fabricatio.models.task import Task
13
13
  from fabricatio.models.tool import Tool, ToolExecutor
14
14
  from fabricatio.models.usages import ToolBoxUsage
15
15
  from fabricatio.parser import JsonCapture, PythonCapture
16
+ from fabricatio.rust_instances import TEMPLATE_MANAGER
16
17
 
17
18
 
18
19
  class ProposeTask(Propose):
fabricatio/config.py CHANGED
@@ -229,9 +229,6 @@ class TemplateConfig(BaseModel):
229
229
  generic_string_template: str = Field(default="generic_string")
230
230
  """The name of the generic string template which will be used to review a string."""
231
231
 
232
- correct_template: str = Field(default="correct")
233
- """The name of the correct template which will be used to correct a string."""
234
-
235
232
  co_validation_template: str = Field(default="co_validation")
236
233
  """The name of the co-validation template which will be used to co-validate a string."""
237
234
 
@@ -241,6 +238,17 @@ class TemplateConfig(BaseModel):
241
238
  check_string_template: str = Field(default="check_string")
242
239
  """The name of the check string template which will be used to check a string."""
243
240
 
241
+ ruleset_requirement_breakdown_template: str = Field(default="ruleset_requirement_breakdown")
242
+ """The name of the ruleset requirement breakdown template which will be used to breakdown a ruleset requirement."""
243
+
244
+ fix_troubled_obj_template: str = Field(default="fix_troubled_obj")
245
+ """The name of the fix troubled object template which will be used to fix a troubled object."""
246
+
247
+ fix_troubled_string_template: str = Field(default="fix_troubled_string")
248
+ """The name of the fix troubled string template which will be used to fix a troubled string."""
249
+
250
+ rule_requirement_template: str = Field(default="rule_requirement")
251
+ """The name of the rule requirement template which will be used to generate a rule requirement."""
244
252
  class MagikaConfig(BaseModel):
245
253
  """Magika configuration class."""
246
254
 
@@ -9,16 +9,18 @@ from abc import abstractmethod
9
9
  from asyncio import Queue, create_task
10
10
  from typing import Any, Dict, Self, Tuple, Type, Union, final
11
11
 
12
- from fabricatio.capabilities.correct import Correct
13
- from fabricatio.capabilities.task import HandleTask, ProposeTask
14
12
  from fabricatio.journal import logger
15
13
  from fabricatio.models.generic import WithBriefing
16
14
  from fabricatio.models.task import Task
17
- from fabricatio.models.usages import ToolBoxUsage
15
+ from fabricatio.models.usages import LLMUsage, ToolBoxUsage
18
16
  from pydantic import Field, PrivateAttr
19
17
 
18
+ OUTPUT_KEY = "task_output"
20
19
 
21
- class Action(WithBriefing, HandleTask, ProposeTask, Correct):
20
+ INPUT_KEY = "task_input"
21
+
22
+
23
+ class Action(WithBriefing, LLMUsage):
22
24
  """Class that represents an action to be executed in a workflow.
23
25
 
24
26
  Actions are the atomic units of work in a workflow. Each action performs
@@ -90,6 +92,10 @@ class Action(WithBriefing, HandleTask, ProposeTask, Correct):
90
92
  return f"## Your personality: \n{self.personality}\n# The action you are going to perform: \n{super().briefing}"
91
93
  return f"# The action you are going to perform: \n{super().briefing}"
92
94
 
95
+ def to_task_output(self)->Self:
96
+ """Set the output key to OUTPUT_KEY and return the action instance."""
97
+ self.output_key=OUTPUT_KEY
98
+ return self
93
99
 
94
100
  class WorkFlow(WithBriefing, ToolBoxUsage):
95
101
  """Class that represents a sequence of actions to be executed for a task.
@@ -97,7 +103,8 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
97
103
  A workflow manages the execution of multiple actions in sequence, passing
98
104
  a shared context between them and handling task lifecycle events.
99
105
  """
100
- description:str =""
106
+
107
+ description: str = ""
101
108
  """The description of the workflow, which describes the workflow's purpose and requirements."""
102
109
 
103
110
  _context: Queue[Dict[str, Any]] = PrivateAttr(default_factory=lambda: Queue(maxsize=1))
@@ -111,10 +118,10 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
111
118
  )
112
119
  """The sequence of actions to be executed, can be action classes or instances."""
113
120
 
114
- task_input_key: str = Field(default="task_input")
121
+ task_input_key: str = Field(default=INPUT_KEY)
115
122
  """Key used to store the input task in the context dictionary."""
116
123
 
117
- task_output_key: str = Field(default="task_output")
124
+ task_output_key: str = Field(default=OUTPUT_KEY)
118
125
  """Key used to extract the final result from the context dictionary."""
119
126
 
120
127
  extra_init_context: Dict[str, Any] = Field(default_factory=dict, frozen=True)
@@ -0,0 +1,25 @@
1
+ """A module containing kwargs types for content correction and checking operations."""
2
+ from fabricatio.models.extra.problem import Improvement
3
+ from fabricatio.models.extra.rule import RuleSet
4
+ from fabricatio.models.generic import SketchedAble
5
+ from fabricatio.models.kwargs_types import ReferencedKwargs
6
+
7
+
8
+ class CorrectKwargs[T: SketchedAble](ReferencedKwargs[T], total=False):
9
+ """Arguments for content correction operations.
10
+
11
+ Extends GenerateKwargs with parameters for correcting content based on
12
+ specific criteria and templates.
13
+ """
14
+
15
+ improvement: Improvement
16
+
17
+
18
+ class CheckKwargs(ReferencedKwargs[Improvement], total=False):
19
+ """Arguments for content checking operations.
20
+
21
+ Extends GenerateKwargs with parameters for checking content against
22
+ specific criteria and templates.
23
+ """
24
+
25
+ ruleset: RuleSet
@@ -0,0 +1 @@
1
+ """A module contains extra models for fabricatio."""
@@ -5,18 +5,21 @@ from typing import List
5
5
  from fabricatio.models.generic import Display, ProposedAble
6
6
 
7
7
 
8
- class JudgeMent(ProposedAble,Display):
8
+ class JudgeMent(ProposedAble, Display):
9
9
  """Represents a judgment result containing supporting/denying evidence and final verdict.
10
10
 
11
11
  The class stores both affirmative and denies evidence, truth and reasons lists along with the final boolean judgment.
12
12
  """
13
+
14
+ issue_to_judge: str
15
+ """The issue to be judged"""
16
+
13
17
  deny_evidence: List[str]
14
18
  """List of clues supporting the denial."""
15
19
 
16
20
  affirm_evidence: List[str]
17
21
  """List of clues supporting the affirmation."""
18
22
 
19
-
20
23
  final_judgement: bool
21
24
  """The final judgment made according to all extracted clues."""
22
25
 
@@ -15,6 +15,7 @@ from fabricatio.models.generic import (
15
15
  PersistentAble,
16
16
  ProposedUpdateAble,
17
17
  ResolveUpdateConflict,
18
+ SequencePatch,
18
19
  )
19
20
 
20
21
 
@@ -29,7 +30,7 @@ class ReferringType(StrEnum):
29
30
  type RefKey = Tuple[str, Optional[str], Optional[str]]
30
31
 
31
32
 
32
- class ArticleRef(CensoredAble, Display, ProposedUpdateAble):
33
+ class ArticleRef(CensoredAble, ProposedUpdateAble):
33
34
  """Reference to a specific chapter, section or subsection within the article. You SHALL not refer to an article component that is external and not present within our own article.
34
35
 
35
36
  Examples:
@@ -120,25 +121,7 @@ class ArticleMetaData(CensoredAble, Display):
120
121
  """Do not add any prefix or suffix to the title. should not contain special characters."""
121
122
 
122
123
 
123
- class Patch[T](ProposedUpdateAble, Display):
124
- """Base class for patches."""
125
-
126
- tweaked: List[T]
127
- """Tweaked content list"""
128
-
129
- def update_from_inner(self, other: Self) -> Self:
130
- """Updates the current instance with the attributes of another instance."""
131
- self.tweaked.clear()
132
- self.tweaked.extend(other.tweaked)
133
- return self
134
-
135
- @classmethod
136
- def default(cls) -> Self:
137
- """Defaults to empty list."""
138
- return cls(tweaked=[])
139
-
140
-
141
- class ArticleRefPatch(Patch[ArticleRef]):
124
+ class ArticleRefSequencePatch(SequencePatch[ArticleRef]):
142
125
  """Patch for article refs."""
143
126
 
144
127
 
@@ -8,14 +8,13 @@ from fabricatio.models.extra.article_base import (
8
8
  ArticleBase,
9
9
  ArticleOutlineBase,
10
10
  ChapterBase,
11
- Patch,
12
11
  SectionBase,
13
12
  SubSectionBase,
14
13
  )
15
14
  from fabricatio.models.extra.article_outline import (
16
15
  ArticleOutline,
17
16
  )
18
- from fabricatio.models.generic import CensoredAble, Display, PersistentAble, WithRef
17
+ from fabricatio.models.generic import CensoredAble, Display, PersistentAble, SequencePatch, WithRef
19
18
  from fabricatio.utils import ok
20
19
 
21
20
 
@@ -32,7 +31,7 @@ class Paragraph(CensoredAble):
32
31
  """The actual content of the paragraph, represented as a string."""
33
32
 
34
33
 
35
- class ArticleParagraphPatch(Patch[Paragraph]):
34
+ class ArticleParagraphSequencePatch(SequencePatch[Paragraph]):
36
35
  """Patch for `Paragraph` list of `ArticleSubsection`."""
37
36
 
38
37
 
@@ -0,0 +1,20 @@
1
+ """A patch class for updating the description and name of a `WithBriefing` object, all fields within this instance will be directly copied onto the target model's field."""
2
+
3
+ from typing import Optional, Type
4
+
5
+ from fabricatio.models.extra.rule import RuleSet
6
+ from fabricatio.models.generic import Patch, WithBriefing
7
+ from pydantic import BaseModel
8
+
9
+
10
+ class BriefingPatch[T: WithBriefing](Patch[T], WithBriefing):
11
+ """Patch class for updating the description and name of a `WithBriefing` object, all fields within this instance will be directly copied onto the target model's field."""
12
+
13
+
14
+ class RuleSetBriefingPatch(BriefingPatch[RuleSet]):
15
+ """Patch class for updating the description and name of a `RuleSet` object, all fields within this instance will be directly copied onto the target model's field."""
16
+ language: str
17
+ @staticmethod
18
+ def ref_cls() -> Optional[Type[BaseModel]]:
19
+ """Get the reference class of the model."""
20
+ return RuleSet
@@ -1,14 +1,16 @@
1
1
  """A class representing a problem-solution pair identified during a review process."""
2
2
 
3
- from typing import List, Literal, Self
3
+ from itertools import chain
4
+ from typing import List, Literal, Optional, Self
4
5
 
5
- from fabricatio.models.generic import Display, ProposedAble, ProposedUpdateAble, WithBriefing
6
+ from fabricatio.journal import logger
7
+ from fabricatio.models.generic import SketchedAble, WithBriefing
6
8
  from fabricatio.utils import ask_edit
7
9
  from questionary import Choice, checkbox, text
8
10
  from rich import print as r_print
9
11
 
10
12
 
11
- class Problem(ProposedAble, WithBriefing, Display):
13
+ class Problem(SketchedAble, WithBriefing):
12
14
  """Represents a problem identified during review."""
13
15
 
14
16
  description: str
@@ -27,11 +29,14 @@ class Problem(ProposedAble, WithBriefing, Display):
27
29
  """Recommended solution or action."""
28
30
 
29
31
 
30
- class Solution(ProposedAble, WithBriefing, Display):
32
+ class Solution(SketchedAble, WithBriefing):
31
33
  """Represents a proposed solution to a problem."""
32
34
 
33
- operation: str
34
- """Description or identifier of the operation."""
35
+ description: str
36
+ """Description of the solution, including a detailed description of the execution steps, and the mechanics, principle or fact."""
37
+
38
+ execute_steps: List[str]
39
+ """A list of steps to execute to implement the solution, which is expected to be able to finally solve the corresponding problem."""
35
40
 
36
41
  feasibility: Literal["low", "medium", "high"]
37
42
  """Feasibility level of the solution."""
@@ -40,7 +45,7 @@ class Solution(ProposedAble, WithBriefing, Display):
40
45
  """Impact level of the solution."""
41
46
 
42
47
 
43
- class ProblemSolutions(ProposedUpdateAble):
48
+ class ProblemSolutions(SketchedAble):
44
49
  """Represents a problem-solution pair identified during a review process."""
45
50
 
46
51
  problem: Problem
@@ -78,10 +83,26 @@ class ProblemSolutions(ProposedUpdateAble):
78
83
  self.solutions = [Solution.model_validate_strings(s) for s in string_seq]
79
84
  return self
80
85
 
86
+ def decided(self) -> bool:
87
+ """Check if the improvement is decided."""
88
+ return len(self.solutions) == 1
89
+
90
+ def final_solution(self) -> Optional[Solution]:
91
+ """Get the final solution."""
92
+ if not self.decided():
93
+ logger.error(
94
+ f"There is more than one solution for problem {self.problem.name}, please decide which solution is eventually adopted."
95
+ )
96
+ return None
97
+ return self.solutions[0]
98
+
81
99
 
82
- class Improvement(ProposedAble, Display):
100
+ class Improvement(SketchedAble):
83
101
  """A class representing an improvement suggestion."""
84
102
 
103
+ focused_on: str
104
+ """The focused on topic of the improvement"""
105
+
85
106
  problem_solutions: List[ProblemSolutions]
86
107
  """Collection of problems identified during review along with their potential solutions."""
87
108
 
@@ -118,3 +139,15 @@ class Improvement(ProposedAble, Display):
118
139
  await to_exam.edit_solutions()
119
140
 
120
141
  return self
142
+
143
+ def decided(self) -> bool:
144
+ """Check if the improvement is decided."""
145
+ return all(ps.decided() for ps in self.problem_solutions)
146
+
147
+ @classmethod
148
+ def gather(cls, *improvements: Self) -> Self:
149
+ """Gather multiple improvements into a single instance."""
150
+ return cls(
151
+ focused_on="\n".join(imp.focused_on for imp in improvements),
152
+ problem_solutions=list(chain(*(imp.problem_solutions for imp in improvements))),
153
+ )
@@ -1,23 +1,40 @@
1
- """A module containing classes related to rule sets and rules."""
1
+ """A module containing classes related to rule sets and rules.
2
+
3
+ This module provides the `Rule` and `RuleSet` classes, which are used to define and manage
4
+ individual rules and collections of rules, respectively. These classes are designed to
5
+ facilitate the creation, organization, and application of rules in various contexts,
6
+ ensuring clarity, consistency, and enforceability. The module supports detailed
7
+ descriptions, examples, and metadata for each rule and rule set, making it suitable for
8
+ complex rule management systems.
9
+ """
2
10
 
3
11
  from typing import List
4
12
 
5
- from fabricatio.models.generic import Described, Display, PersistentAble, ProposedAble, WithBriefing
13
+ from fabricatio.models.generic import Language, PersistentAble, SketchedAble, WithBriefing
6
14
 
7
15
 
8
- class Rule(WithBriefing,ProposedAble,Display):
16
+ class Rule(WithBriefing,Language, SketchedAble,PersistentAble):
9
17
  """Represents a rule or guideline for a specific topic."""
10
18
 
19
+
11
20
  violation_examples: List[str]
12
- """Examples of violations of the rule."""
21
+ """A list of concrete examples demonstrating violations of this rule. Each example should
22
+ be a clear scenario or case that illustrates how the rule can be broken, including the
23
+ context, actions, and consequences of the violation. These examples should help in
24
+ understanding the boundaries of the rule."""
25
+
13
26
  compliance_examples: List[str]
14
- """Examples of how to comply with the rule."""
27
+ """A list of concrete examples demonstrating proper compliance with this rule. Each example
28
+ should be a clear scenario or case that illustrates how to correctly follow the rule,
29
+ including the context, actions, and positive outcomes of compliance. These examples should
30
+ serve as practical guidance for implementing the rule correctly."""
15
31
 
16
32
 
17
- class RuleSet(ProposedAble, Display, PersistentAble, Described):
33
+ class RuleSet( SketchedAble, PersistentAble, WithBriefing,Language):
18
34
  """Represents a collection of rules and guidelines for a particular topic."""
19
35
 
20
- title: str
21
- """The title of the rule set."""
22
36
  rules: List[Rule]
23
- """The rules and guidelines contained in the rule set."""
37
+ """The collection of rules and guidelines contained in this rule set. Each rule should be
38
+ a well-defined, specific guideline that contributes to the overall purpose of the rule set.
39
+ The rules should be logically organized and consistent with each other, forming a coherent
40
+ framework for the topic or domain covered by the rule set."""