fabricatio 0.2.5.dev1__cp312-cp312-manylinux_2_34_x86_64.whl → 0.2.5.dev3__cp312-cp312-manylinux_2_34_x86_64.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.
fabricatio/_rust.pyi CHANGED
@@ -2,60 +2,101 @@ from pathlib import Path
2
2
  from typing import Any, Dict, List, Optional
3
3
 
4
4
  class TemplateManager:
5
- """TemplateManager class for managing handlebars templates."""
5
+ """Template rendering engine using Handlebars templates.
6
+
7
+ This manager handles template discovery, loading, and rendering
8
+ through a wrapper around the handlebars-rust engine.
9
+
10
+ See: https://crates.io/crates/handlebars
11
+ """
6
12
  def __init__(
7
13
  self, template_dirs: List[Path], suffix: Optional[str] = None, active_loading: Optional[bool] = None
8
14
  ) -> None:
9
15
  """Initialize the template manager.
10
16
 
11
17
  Args:
12
- template_dirs (List[Path]): A list of paths to directories containing templates.
13
- suffix (str, optional): The suffix of template files. None means 'hbs' suffix.
14
- active_loading (bool, optional): Whether to enable active loading of templates.
18
+ template_dirs: List of directories containing template files
19
+ suffix: File extension for templates (defaults to 'hbs')
20
+ active_loading: Whether to enable dev mode for reloading templates on change
15
21
  """
16
22
 
17
23
  @property
18
24
  def template_count(self) -> int:
19
- """Get the number of templates discovered."""
25
+ """Returns the number of currently loaded templates."""
20
26
 
21
27
  def get_template_source(self, name: str) -> Optional[str]:
22
- """Get the source path of a template by name.
28
+ """Get the filesystem path for a template.
23
29
 
24
30
  Args:
25
- name (str): The name of the template to retrieve.
31
+ name: Template name (without extension)
26
32
 
27
33
  Returns:
28
- Optional[str]: The source path of the template.
34
+ Path to the template file if found, None otherwise
29
35
  """
30
36
 
31
37
  def discover_templates(self) -> None:
32
- """Discover templates in the specified directories."""
38
+ """Scan template directories and load available templates.
39
+
40
+ This refreshes the template cache, finding any new or modified templates.
41
+ """
33
42
 
34
43
  def render_template(self, name: str, data: Dict[str, Any]) -> str:
35
- """Render a template with the given name and data.
44
+ """Render a template with context data.
36
45
 
37
46
  Args:
38
- name (str): The name of the template to render.
39
- data (Dict[str, Any]): The data to pass to the template.
47
+ name: Template name (without extension)
48
+ data: Context dictionary to provide variables to the template
40
49
 
41
50
  Returns:
42
- str: The rendered template.
51
+ Rendered template content as string
52
+
53
+ Raises:
54
+ RuntimeError: If template rendering fails
43
55
  """
44
56
 
45
57
  def blake3_hash(content: bytes) -> str:
46
- """Calculate the BLAKE3 hash of the given data.
58
+ """Calculate the BLAKE3 cryptographic hash of data.
47
59
 
48
60
  Args:
49
- content (bytes): The data to hash.
61
+ content: Bytes to be hashed
50
62
 
51
63
  Returns:
52
- str: The BLAKE3 hash of the data.
64
+ Hex-encoded BLAKE3 hash string
53
65
  """
54
66
 
55
67
  class BibManager:
56
- """BibManager class for managing BibTeX files."""
68
+ """BibTeX bibliography manager for parsing and querying citation data."""
69
+
57
70
  def __init__(self, path: str) -> None:
58
- """Initialize the BibManager with the given path."""
71
+ """Initialize the bibliography manager.
72
+
73
+ Args:
74
+ path: Path to BibTeX (.bib) file to load
75
+
76
+ Raises:
77
+ RuntimeError: If file cannot be read or parsed
78
+ """
79
+
80
+ def get_cite_key(self, title: str) -> Optional[str]:
81
+ """Find citation key by exact title match.
59
82
 
60
- def get_cite_key(self, title: str) -> str:
61
- """Get the cite key for the given title."""
83
+ Args:
84
+ title: Full title to search for (case-insensitive)
85
+
86
+ Returns:
87
+ Citation key if exact match found, None otherwise
88
+ """
89
+
90
+ def get_cite_key_fuzzy(self, query: str) -> Optional[str]:
91
+ """Find best matching citation using fuzzy text search.
92
+
93
+ Args:
94
+ query: Search term to find in bibliography entries
95
+
96
+ Returns:
97
+ Citation key of best matching entry, or None if no good match
98
+
99
+ Notes:
100
+ Uses nucleo_matcher for high-quality fuzzy text searching
101
+ See: https://crates.io/crates/nucleo-matcher
102
+ """
@@ -1,3 +1,5 @@
1
+ """Some necessary instances."""
2
+
1
3
  from fabricatio._rust import TemplateManager
2
4
  from fabricatio.config import configs
3
5
 
@@ -15,7 +15,7 @@ class Propose[M: ProposedAble](LLMUsage):
15
15
  self,
16
16
  cls: Type[M],
17
17
  prompt: List[str],
18
- **kwargs: Unpack[GenerateKwargs],
18
+ **kwargs: Unpack[GenerateKwargs[M]],
19
19
  ) -> List[M]: ...
20
20
 
21
21
  @overload
@@ -23,14 +23,14 @@ class Propose[M: ProposedAble](LLMUsage):
23
23
  self,
24
24
  cls: Type[M],
25
25
  prompt: str,
26
- **kwargs: Unpack[GenerateKwargs],
26
+ **kwargs: Unpack[GenerateKwargs[M]],
27
27
  ) -> M: ...
28
28
 
29
29
  async def propose(
30
30
  self,
31
31
  cls: Type[M],
32
32
  prompt: List[str] | str,
33
- **kwargs: Unpack[GenerateKwargs],
33
+ **kwargs: Unpack[GenerateKwargs[M]],
34
34
  ) -> List[M] | M:
35
35
  """Asynchronously proposes a task based on a given prompt and parameters.
36
36
 
@@ -2,9 +2,9 @@
2
2
 
3
3
  from asyncio import gather
4
4
  from itertools import permutations
5
+ from random import sample
5
6
  from typing import Dict, List, Set, Tuple, Union, Unpack, overload
6
7
 
7
- from cache import AsyncLRU
8
8
  from fabricatio._rust_instances import template_manager
9
9
  from fabricatio.config import configs
10
10
  from fabricatio.journal import logger
@@ -17,7 +17,11 @@ from pydantic import NonNegativeInt, PositiveInt
17
17
 
18
18
 
19
19
  class GiveRating(WithBriefing, LLMUsage):
20
- """A class that provides functionality to rate tasks based on a rating manual and score range."""
20
+ """A class that provides functionality to rate tasks based on a rating manual and score range.
21
+
22
+ References:
23
+ Lu X, Li J, Takeuchi K, et al. AHP-powered LLM reasoning for multi-criteria evaluation of open-ended responses[A/OL]. arXiv, 2024. DOI: 10.48550/arXiv.2410.01246.
24
+ """
21
25
 
22
26
  async def rate_fine_grind(
23
27
  self,
@@ -113,7 +117,6 @@ class GiveRating(WithBriefing, LLMUsage):
113
117
  return await gather(*[self.rate_fine_grind(item, manual, score_range, **kwargs) for item in to_rate])
114
118
  raise ValueError("to_rate must be a string or a list of strings")
115
119
 
116
- @AsyncLRU(maxsize=32)
117
120
  async def draft_rating_manual(
118
121
  self, topic: str, criteria: Set[str], **kwargs: Unpack[ValidateKwargs]
119
122
  ) -> Dict[str, str]:
@@ -189,6 +192,7 @@ class GiveRating(WithBriefing, LLMUsage):
189
192
  self,
190
193
  topic: str,
191
194
  examples: List[str],
195
+ m: NonNegativeInt = 0,
192
196
  reasons_count: PositiveInt = 2,
193
197
  criteria_count: PositiveInt = 5,
194
198
  **kwargs: Unpack[ValidateKwargs],
@@ -201,13 +205,21 @@ class GiveRating(WithBriefing, LLMUsage):
201
205
  Parameters:
202
206
  topic (str): The subject topic for the rating criteria.
203
207
  examples (List[str]): A list of example texts to analyze.
208
+ m (NonNegativeInt, optional): The number of examples to sample from the provided list. Defaults to 0 (no sampling).
204
209
  reasons_count (PositiveInt, optional): The number of reasons to extract from each pair of examples. Defaults to 2.
205
210
  criteria_count (PositiveInt, optional): The final number of rating criteria to draft. Defaults to 5.
206
211
  **kwargs (Unpack[ValidateKwargs]): Additional keyword arguments for validation.
207
212
 
208
213
  Returns:
209
214
  Set[str]: A set of drafted rating criteria.
215
+
216
+ Warnings:
217
+ Since this function uses pairwise comparisons, it may not be suitable for large lists of examples.
218
+ For that reason, consider using a smaller list of examples or setting `m` to a non-zero value smaller than the length of the examples.
210
219
  """
220
+ if m:
221
+ examples = sample(examples, m)
222
+
211
223
  kwargs = GenerateKwargs(system_message=f"# your personal briefing: \n{self.briefing}", **kwargs)
212
224
  # extract reasons from the comparison of ordered pairs of extracted from examples
213
225
  reasons = flatten(
@@ -1,60 +1,157 @@
1
1
  """A module that provides functionality to rate tasks based on a rating manual and score range."""
2
2
 
3
- from typing import List, Optional, Set, Unpack
3
+ from typing import List, Optional, Self, Set, Unpack
4
4
 
5
5
  from fabricatio import template_manager
6
6
  from fabricatio.capabilities.propose import Propose
7
7
  from fabricatio.capabilities.rating import GiveRating
8
8
  from fabricatio.config import configs
9
- from fabricatio.models.generic import Display, ProposedAble, WithBriefing
9
+ from fabricatio.models.generic import Base, Display, ProposedAble, WithBriefing
10
10
  from fabricatio.models.kwargs_types import GenerateKwargs, ReviewKwargs
11
11
  from fabricatio.models.task import Task
12
12
  from pydantic import PrivateAttr
13
+ from questionary import Choice, checkbox
14
+ from rich import print
15
+
16
+
17
+ class ProblemSolutions(Base):
18
+ """Represents a problem-solution pair identified during a review process.
19
+
20
+ This class encapsulates a single problem with its corresponding potential solutions,
21
+ providing a structured way to manage review findings.
22
+
23
+ Attributes:
24
+ problem (str): The problem statement identified during review.
25
+ solutions (List[str]): A collection of potential solutions to address the problem.
26
+ """
27
+
28
+ problem: str
29
+ """The problem identified in the review."""
30
+ solutions: List[str]
31
+ """A collection of potential solutions to address the problem."""
32
+
33
+ def update_problem(self, problem: str) -> Self:
34
+ """Update the problem description.
35
+
36
+ Args:
37
+ problem (str): The new problem description to replace the current one.
38
+
39
+ Returns:
40
+ Self: The current instance with updated problem description.
41
+ """
42
+ self.problem = problem
43
+ return self
44
+
45
+ def update_solutions(self, solutions: List[str]) -> Self:
46
+ """Update the list of potential solutions.
47
+
48
+ Args:
49
+ solutions (List[str]): The new collection of solutions to replace the current ones.
50
+
51
+ Returns:
52
+ Self: The current instance with updated solutions.
53
+ """
54
+ self.solutions = solutions
55
+ return self
13
56
 
14
57
 
15
58
  class ReviewResult[T](ProposedAble, Display):
16
- """Class that represents the result of a review.
59
+ """Represents the outcome of a review process with identified problems and solutions.
17
60
 
18
- This class holds the problems identified in a review and their proposed solutions,
19
- along with a reference to the reviewed object.
61
+ This class maintains a structured collection of problems found during a review,
62
+ their proposed solutions, and a reference to the original reviewed object.
20
63
 
21
64
  Attributes:
22
- existing_problems (List[str]): List of problems identified in the review.
23
- proposed_solutions (List[str]): List of proposed solutions to the problems identified in the review.
65
+ review_topic (str): The subject or focus area of the review.
66
+ problem_solutions (List[ProblemSolutions]): Collection of problems identified
67
+ during review along with their potential solutions.
24
68
 
25
69
  Type Parameters:
26
70
  T: The type of the object being reviewed.
27
71
  """
28
72
 
29
- existing_problems: List[str]
30
- """List of problems identified in the review."""
73
+ review_topic: str
74
+ """The subject or focus area of the review."""
31
75
 
32
- proposed_solutions: List[str]
33
- """List of proposed solutions to the problems identified in the review."""
76
+ problem_solutions: List[ProblemSolutions]
77
+ """Collection of problems identified during review along with their potential solutions."""
34
78
 
35
79
  _ref: T = PrivateAttr(None)
36
- """Reference to the object being reviewed."""
80
+ """Reference to the original object that was reviewed."""
81
+
82
+ def update_topic(self, topic: str) -> Self:
83
+ """Update the review topic.
84
+
85
+ Args:
86
+ topic (str): The new topic to be associated with this review.
87
+
88
+ Returns:
89
+ Self: The current instance with updated review topic.
90
+ """
91
+ self.review_topic = topic
92
+ return self
37
93
 
38
94
  def update_ref[K](self, ref: K) -> "ReviewResult[K]":
39
- """Update the reference to the object being reviewed.
95
+ """Update the reference to the reviewed object.
40
96
 
41
97
  Args:
42
- ref (K): The new reference to the object being reviewed.
98
+ ref (K): The new reference object to be associated with this review.
43
99
 
44
100
  Returns:
45
- ReviewResult[K]: The updated instance of the ReviewResult class with the new reference type.
101
+ ReviewResult[K]: The current instance with updated reference type.
46
102
  """
47
103
  self._ref = ref
48
104
  return self
49
105
 
50
106
  def deref(self) -> T:
51
- """Dereference the object being reviewed.
107
+ """Retrieve the referenced object that was reviewed.
52
108
 
53
109
  Returns:
54
- T: The object being reviewed.
110
+ T: The original object that was reviewed.
55
111
  """
56
112
  return self._ref
57
113
 
114
+ async def supervisor_check(self, check_solutions: bool = False) -> Self:
115
+ """Perform an interactive review session to filter problems and solutions.
116
+
117
+ Presents an interactive prompt allowing a supervisor to select which
118
+ problems (and optionally solutions) should be retained in the final review.
119
+
120
+ Args:
121
+ check_solutions (bool, optional): When True, also prompts for filtering
122
+ individual solutions for each retained problem. Defaults to False.
123
+
124
+ Returns:
125
+ Self: The current instance with filtered problems and solutions.
126
+ """
127
+ if isinstance(self._ref, str):
128
+ display = self._ref
129
+ elif isinstance(self._ref, WithBriefing):
130
+ display = self._ref.briefing
131
+ elif isinstance(self._ref, Display):
132
+ display = self._ref.display()
133
+ else:
134
+ raise TypeError(f"Unsupported type for review: {type(self._ref)}")
135
+ # Choose the problems to retain
136
+ print(display)
137
+ chosen_ones: List[ProblemSolutions] = await checkbox(
138
+ f"Please choose the problems you want to retain.(Default: retain all)\n\t`{self.review_topic}`",
139
+ choices=[Choice(p.problem, p, checked=True) for p in self.problem_solutions],
140
+ ).ask_async()
141
+ if not check_solutions:
142
+ self.problem_solutions = chosen_ones
143
+ return self
144
+
145
+ # Choose the solutions to retain
146
+ for to_exam in chosen_ones:
147
+ to_exam.update_solutions(
148
+ await checkbox(
149
+ f"Please choose the solutions you want to retain.(Default: retain all)\n\t`{to_exam.problem}`",
150
+ choices=[Choice(s, s, checked=True) for s in to_exam.solutions],
151
+ ).ask_async()
152
+ )
153
+ return self
154
+
58
155
 
59
156
  class Review(GiveRating, Propose):
60
157
  """Class that provides functionality to review tasks and strings using a language model.
@@ -84,7 +181,11 @@ class Review(GiveRating, Propose):
84
181
  return await self.review_obj(task, **kwargs)
85
182
 
86
183
  async def review_string(
87
- self, text: str, topic: str, criteria: Optional[Set[str]] = None, **kwargs: Unpack[GenerateKwargs]
184
+ self,
185
+ text: str,
186
+ topic: str,
187
+ criteria: Optional[Set[str]] = None,
188
+ **kwargs: Unpack[GenerateKwargs[ReviewResult[str]]],
88
189
  ) -> ReviewResult[str]:
89
190
  """Review a string based on specified topic and criteria.
90
191
 
@@ -111,7 +212,7 @@ class Review(GiveRating, Propose):
111
212
  ),
112
213
  **kwargs,
113
214
  )
114
- return res.update_ref(text)
215
+ return res.update_ref(text).update_topic(topic)
115
216
 
116
217
  async def review_obj[M: (Display, WithBriefing)](self, obj: M, **kwargs: Unpack[ReviewKwargs]) -> ReviewResult[M]:
117
218
  """Review an object that implements Display or WithBriefing interface.
fabricatio/config.py CHANGED
@@ -3,6 +3,7 @@
3
3
  from typing import List, Literal, Optional
4
4
 
5
5
  from appdirs import user_config_dir
6
+ from litellm.types.caching import LiteLLMCacheType
6
7
  from pydantic import (
7
8
  BaseModel,
8
9
  ConfigDict,
@@ -25,6 +26,8 @@ from pydantic_settings import (
25
26
  TomlConfigSettingsSource,
26
27
  )
27
28
 
29
+ from fabricatio.models.kwargs_types import CacheKwargs
30
+
28
31
  ROAMING_DIR = user_config_dir("fabricatio", "", roaming=True)
29
32
 
30
33
 
@@ -265,6 +268,19 @@ class RagConfig(BaseModel):
265
268
  """The dimensions of the Milvus server."""
266
269
 
267
270
 
271
+ class CacheConfig(BaseModel):
272
+ """cache configuration class, uses litellm as cache backend. more info see https://docs.litellm.ai/docs/caching/all_caches."""
273
+
274
+ model_config = ConfigDict(use_attribute_docstrings=True)
275
+
276
+ type: Optional[LiteLLMCacheType] = None
277
+ """The type of cache to use. If None, the default cache type will be used."""
278
+ params: CacheKwargs = Field(default_factory=CacheKwargs)
279
+ """The parameters for the cache. If type is None, the default parameters will be used."""
280
+ enabled: bool = Field(default=False)
281
+ """Whether to enable cache."""
282
+
283
+
268
284
  class Settings(BaseSettings):
269
285
  """Application settings class.
270
286
 
@@ -314,6 +330,9 @@ class Settings(BaseSettings):
314
330
  rag: RagConfig = Field(default_factory=RagConfig)
315
331
  """RAG Configuration"""
316
332
 
333
+ cache: CacheConfig = Field(default_factory=CacheConfig)
334
+ """Cache Configuration"""
335
+
317
336
  @classmethod
318
337
  def settings_customise_sources(
319
338
  cls,
fabricatio/fs/__init__.py CHANGED
@@ -7,6 +7,7 @@ from fabricatio.fs.curd import (
7
7
  delete_directory,
8
8
  delete_file,
9
9
  dump_text,
10
+ gather_files,
10
11
  move_file,
11
12
  tree,
12
13
  )
@@ -19,6 +20,7 @@ __all__ = [
19
20
  "delete_directory",
20
21
  "delete_file",
21
22
  "dump_text",
23
+ "gather_files",
22
24
  "magika",
23
25
  "move_file",
24
26
  "safe_json_read",
fabricatio/fs/curd.py CHANGED
@@ -134,3 +134,16 @@ def absolute_path(path: str | Path | PathLike) -> str:
134
134
  str: The absolute path of the file or directory.
135
135
  """
136
136
  return Path(path).expanduser().resolve().as_posix()
137
+
138
+
139
+ def gather_files(directory: str | Path | PathLike, extension: str) -> list[str]:
140
+ """Gather all files with a specific extension in a directory.
141
+
142
+ Args:
143
+ directory (str, Path, PathLike): The directory to search in.
144
+ extension (str): The file extension to look for.
145
+
146
+ Returns:
147
+ list[str]: A list of file paths with the specified extension.
148
+ """
149
+ return [file.as_posix() for file in Path(directory).rglob(f"*.{extension}")]
fabricatio/journal.py CHANGED
@@ -18,7 +18,6 @@ logger.add(
18
18
  )
19
19
  logger.add(sys.stderr, level=configs.debug.log_level)
20
20
 
21
-
22
21
  if __name__ == "__main__":
23
22
  logger.debug("This is a trace message.")
24
23
  logger.info("This is an information message.")
@@ -122,17 +122,16 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
122
122
  current_action = None
123
123
  try:
124
124
  for step in self._instances:
125
- logger.debug(f"Executing step: {step.name}")
125
+ logger.debug(f"Executing step: {(current_action := step.name)}")
126
126
  act_task = create_task(step.act(await self._context.get()))
127
127
  if task.is_cancelled():
128
128
  act_task.cancel(f"Cancelled by task: {task.name}")
129
129
  break
130
130
  modified_ctx = await act_task
131
131
  await self._context.put(modified_ctx)
132
- current_action = step.name
133
132
  logger.info(f"Finished executing workflow: {self.name}")
134
- final_ctx = await self._context.get()
135
- if self.task_output_key not in final_ctx:
133
+
134
+ if self.task_output_key not in (final_ctx := await self._context.get()):
136
135
  logger.warning(
137
136
  f"Task output key: {self.task_output_key} not found in the context, None will be returned. You can check if `Action.output_key` is set the same as `WorkFlow.task_output_key`."
138
137
  )
@@ -1,19 +1,28 @@
1
1
  """This module contains the types for the keyword arguments of the methods in the models module."""
2
2
 
3
- from typing import List, NotRequired, Set, TypedDict
3
+ from typing import Any, List, NotRequired, Set, TypedDict
4
4
 
5
+ from litellm.caching.caching import CacheMode
6
+ from litellm.types.caching import CachingSupportedCallTypes
5
7
  from pydantic import NonNegativeFloat, NonNegativeInt, PositiveInt
6
8
 
7
9
 
8
10
  class CollectionSimpleConfigKwargs(TypedDict):
9
- """A type representing the configuration for a collection."""
11
+ """Configuration parameters for a vector collection.
12
+
13
+ These arguments are typically used when configuring connections to vector databases.
14
+ """
10
15
 
11
16
  dimension: NotRequired[int]
12
17
  timeout: NotRequired[float]
13
18
 
14
19
 
15
20
  class FetchKwargs(TypedDict):
16
- """A type representing the keyword arguments for the fetch method."""
21
+ """Arguments for fetching data from vector collections.
22
+
23
+ Controls how data is retrieved from vector databases, including filtering
24
+ and result limiting parameters.
25
+ """
17
26
 
18
27
  collection_name: NotRequired[str]
19
28
  similarity_threshold: NotRequired[float]
@@ -21,7 +30,11 @@ class FetchKwargs(TypedDict):
21
30
 
22
31
 
23
32
  class EmbeddingKwargs(TypedDict):
24
- """A type representing the keyword arguments for the embedding method."""
33
+ """Configuration parameters for text embedding operations.
34
+
35
+ These settings control the behavior of embedding models that convert text
36
+ to vector representations.
37
+ """
25
38
 
26
39
  model: NotRequired[str]
27
40
  dimensions: NotRequired[int]
@@ -30,7 +43,11 @@ class EmbeddingKwargs(TypedDict):
30
43
 
31
44
 
32
45
  class LLMKwargs(TypedDict):
33
- """A type representing the keyword arguments for the LLM (Large Language Model) usage."""
46
+ """Configuration parameters for language model inference.
47
+
48
+ These arguments control the behavior of large language model calls,
49
+ including generation parameters and caching options.
50
+ """
34
51
 
35
52
  model: NotRequired[str]
36
53
  temperature: NotRequired[NonNegativeFloat]
@@ -40,28 +57,90 @@ class LLMKwargs(TypedDict):
40
57
  stream: NotRequired[bool]
41
58
  timeout: NotRequired[PositiveInt]
42
59
  max_retries: NotRequired[PositiveInt]
60
+ no_cache: NotRequired[bool] # If use cache in this call
61
+ no_store: NotRequired[bool] # If store the response of this call to cache
62
+ cache_ttl: NotRequired[int] # how long the stored cache is alive, in seconds
63
+ s_maxage: NotRequired[int] # max accepted age of cached response, in seconds
43
64
 
44
65
 
45
- class ValidateKwargs(LLMKwargs):
46
- """A type representing the keyword arguments for the validate method."""
66
+ class ValidateKwargs[T](LLMKwargs):
67
+ """Arguments for content validation operations.
47
68
 
69
+ Extends LLMKwargs with additional parameters specific to validation tasks,
70
+ such as limiting the number of validation attempts.
71
+ """
72
+
73
+ default: NotRequired[T]
48
74
  max_validations: NotRequired[PositiveInt]
49
75
 
50
76
 
51
77
  class GenerateKwargs(ValidateKwargs):
52
- """A type representing the keyword arguments for the generate method."""
78
+ """Arguments for content generation operations.
79
+
80
+ Extends ValidateKwargs with parameters specific to text generation,
81
+ including system prompt configuration.
82
+ """
53
83
 
54
84
  system_message: NotRequired[str]
55
85
 
56
86
 
57
87
  class ReviewKwargs(GenerateKwargs):
58
- """A type representing the keyword arguments for the review method."""
88
+ """Arguments for content review operations.
89
+
90
+ Extends GenerateKwargs with parameters for evaluating content against
91
+ specific topics and review criteria.
92
+ """
59
93
 
60
94
  topic: str
61
95
  criteria: NotRequired[Set[str]]
62
96
 
63
97
 
64
98
  class ChooseKwargs(GenerateKwargs):
65
- """A type representing the keyword arguments for the choose method."""
99
+ """Arguments for selection operations.
100
+
101
+ Extends GenerateKwargs with parameters for selecting among options,
102
+ such as the number of items to choose.
103
+ """
66
104
 
67
105
  k: NotRequired[NonNegativeInt]
106
+
107
+
108
+ class CacheKwargs(TypedDict, total=False):
109
+ """Configuration parameters for the caching system.
110
+
111
+ These arguments control the behavior of various caching backends,
112
+ including in-memory, Redis, S3, and vector database caching options.
113
+ """
114
+
115
+ mode: NotRequired[CacheMode] # when default_on cache is always on, when default_off cache is opt in
116
+ host: NotRequired[str]
117
+ port: NotRequired[str]
118
+ password: NotRequired[str]
119
+ namespace: NotRequired[str]
120
+ ttl: NotRequired[float]
121
+ default_in_memory_ttl: NotRequired[float]
122
+ default_in_redis_ttl: NotRequired[float]
123
+ similarity_threshold: NotRequired[float]
124
+ supported_call_types: NotRequired[List[CachingSupportedCallTypes]]
125
+ # s3 Bucket, boto3 configuration
126
+ s3_bucket_name: NotRequired[str]
127
+ s3_region_name: NotRequired[str]
128
+ s3_api_version: NotRequired[str]
129
+ s3_use_ssl: NotRequired[bool]
130
+ s3_verify: NotRequired[bool | str]
131
+ s3_endpoint_url: NotRequired[str]
132
+ s3_aws_access_key_id: NotRequired[str]
133
+ s3_aws_secret_access_key: NotRequired[str]
134
+ s3_aws_session_token: NotRequired[str]
135
+ s3_config: NotRequired[Any]
136
+ s3_path: NotRequired[str]
137
+ redis_semantic_cache_use_async: bool
138
+ redis_semantic_cache_embedding_model: str
139
+ redis_flush_size: NotRequired[int]
140
+ redis_startup_nodes: NotRequired[List]
141
+ disk_cache_dir: Any
142
+ qdrant_api_base: NotRequired[str]
143
+ qdrant_api_key: NotRequired[str]
144
+ qdrant_collection_name: NotRequired[str]
145
+ qdrant_quantization_config: NotRequired[str]
146
+ qdrant_semantic_cache_embedding_model: str
fabricatio/models/role.py CHANGED
@@ -15,7 +15,7 @@ from pydantic import Field
15
15
  class Role(ProposeTask, HandleTask, Review):
16
16
  """Class that represents a role with a registry of events and workflows."""
17
17
 
18
- registry: dict[Event | str, WorkFlow] = Field(...)
18
+ registry: dict[Event | str, WorkFlow] = Field(default_factory=dict)
19
19
  """ The registry of events and workflows."""
20
20
 
21
21
  toolboxes: Set[ToolBox] = Field(default_factory=set)
@@ -25,6 +25,10 @@ from litellm.utils import CustomStreamWrapper
25
25
  from more_itertools import duplicates_everseen
26
26
  from pydantic import Field, NonNegativeInt, PositiveInt
27
27
 
28
+ if configs.cache.enabled:
29
+ litellm.enable_cache(type=configs.cache.type, **configs.cache.params)
30
+ logger.success(f"{configs.cache.type.name} Cache enabled")
31
+
28
32
 
29
33
  class LLMUsage(ScopedConfig):
30
34
  """Class that manages LLM (Large Language Model) usage parameters and methods."""
@@ -63,6 +67,12 @@ class LLMUsage(ScopedConfig):
63
67
  max_retries=kwargs.get("max_retries") or self.llm_max_retries or configs.llm.max_retries,
64
68
  api_key=(self.llm_api_key or configs.llm.api_key).get_secret_value(),
65
69
  base_url=(self.llm_api_endpoint or configs.llm.api_endpoint).unicode_string(),
70
+ cache={
71
+ "no-cache": kwargs.get("no_cache"),
72
+ "no-store": kwargs.get("no_store"),
73
+ "cache-ttl": kwargs.get("cache_ttl"),
74
+ "s-maxage": kwargs.get("s_maxage"),
75
+ },
66
76
  )
67
77
 
68
78
  async def ainvoke(
@@ -105,14 +115,14 @@ class LLMUsage(ScopedConfig):
105
115
  async def aask(
106
116
  self,
107
117
  question: List[str],
108
- system_message: Optional[List[str]] = None,
118
+ system_message: List[str],
109
119
  **kwargs: Unpack[LLMKwargs],
110
120
  ) -> List[str]: ...
111
121
  @overload
112
122
  async def aask(
113
123
  self,
114
124
  question: str,
115
- system_message: Optional[List[str]] = None,
125
+ system_message: List[str],
116
126
  **kwargs: Unpack[LLMKwargs],
117
127
  ) -> List[str]: ...
118
128
  @overload
@@ -148,52 +158,52 @@ class LLMUsage(ScopedConfig):
148
158
  str | List[str]: The content of the model's response message.
149
159
  """
150
160
  system_message = system_message or ""
151
- match (isinstance(question, list), isinstance(system_message, list)):
152
- case (True, True):
161
+ match (question, system_message):
162
+ case (list(q_seq), list(sm_seq)):
153
163
  res = await gather(
154
164
  *[
155
165
  self.ainvoke(n=1, question=q, system_message=sm, **kwargs)
156
- for q, sm in zip(question, system_message, strict=True)
166
+ for q, sm in zip(q_seq, sm_seq, strict=True)
157
167
  ]
158
168
  )
159
169
  return [r.pop().message.content for r in res]
160
- case (True, False):
161
- res = await gather(
162
- *[self.ainvoke(n=1, question=q, system_message=system_message, **kwargs) for q in question]
163
- )
170
+ case (list(q_seq), str(sm)):
171
+ res = await gather(*[self.ainvoke(n=1, question=q, system_message=sm, **kwargs) for q in q_seq])
164
172
  return [r.pop().message.content for r in res]
165
- case (False, True):
166
- res = await gather(
167
- *[self.ainvoke(n=1, question=question, system_message=sm, **kwargs) for sm in system_message]
168
- )
173
+ case (str(q), list(sm_seq)):
174
+ res = await gather(*[self.ainvoke(n=1, question=q, system_message=sm, **kwargs) for sm in sm_seq])
169
175
  return [r.pop().message.content for r in res]
170
- case (False, False):
171
- return (
172
- (
173
- await self.ainvoke(
174
- n=1,
175
- question=question,
176
- system_message=system_message,
177
- **kwargs,
178
- )
179
- ).pop()
180
- ).message.content
176
+ case (str(q), str(sm)):
177
+ return ((await self.ainvoke(n=1, question=q, system_message=sm, **kwargs)).pop()).message.content
181
178
  case _:
182
179
  raise RuntimeError("Should not reach here.")
183
180
 
181
+ @overload
184
182
  async def aask_validate[T](
185
183
  self,
186
184
  question: str,
187
185
  validator: Callable[[str], T | None],
186
+ default: T,
188
187
  max_validations: PositiveInt = 2,
189
188
  system_message: str = "",
190
189
  **kwargs: Unpack[LLMKwargs],
191
- ) -> T:
190
+ ) -> T: ...
191
+
192
+ async def aask_validate[T](
193
+ self,
194
+ question: str,
195
+ validator: Callable[[str], T | None],
196
+ default: Optional[T] = None,
197
+ max_validations: PositiveInt = 2,
198
+ system_message: str = "",
199
+ **kwargs: Unpack[LLMKwargs],
200
+ ) -> Optional[T]:
192
201
  """Asynchronously asks a question and validates the response using a given validator.
193
202
 
194
203
  Args:
195
204
  question (str): The question to ask.
196
205
  validator (Callable[[str], T | None]): A function to validate the response.
206
+ default (T | None): Default value to return if validation fails. Defaults to None.
197
207
  max_validations (PositiveInt): Maximum number of validation attempts. Defaults to 2.
198
208
  system_message (str): System message to include in the request. Defaults to an empty string.
199
209
  **kwargs (Unpack[LLMKwargs]): Additional keyword arguments for the LLM usage.
@@ -201,8 +211,6 @@ class LLMUsage(ScopedConfig):
201
211
  Returns:
202
212
  T: The validated response.
203
213
 
204
- Raises:
205
- ValueError: If the response fails to validate after the maximum number of attempts.
206
214
  """
207
215
  for i in range(max_validations):
208
216
  if (
@@ -214,14 +222,17 @@ class LLMUsage(ScopedConfig):
214
222
  ) and (validated := validator(response)):
215
223
  logger.debug(f"Successfully validated the response at {i}th attempt.")
216
224
  return validated
217
- logger.error(err := f"Failed to validate the response after {max_validations} attempts.")
218
- raise ValueError(err)
225
+ kwargs["no_cache"] = True
226
+ logger.debug("Closed the cache for the next attempt")
227
+ if default is None:
228
+ logger.error(f"Failed to validate the response after {max_validations} attempts.")
229
+ return default
219
230
 
220
231
  async def aask_validate_batch[T](
221
232
  self,
222
233
  questions: List[str],
223
234
  validator: Callable[[str], T | None],
224
- **kwargs: Unpack[GenerateKwargs],
235
+ **kwargs: Unpack[GenerateKwargs[T]],
225
236
  ) -> List[T]:
226
237
  """Asynchronously asks a batch of questions and validates the responses using a given validator.
227
238
 
@@ -238,7 +249,9 @@ class LLMUsage(ScopedConfig):
238
249
  """
239
250
  return await gather(*[self.aask_validate(question, validator, **kwargs) for question in questions])
240
251
 
241
- async def aliststr(self, requirement: str, k: NonNegativeInt = 0, **kwargs: Unpack[GenerateKwargs]) -> List[str]:
252
+ async def aliststr(
253
+ self, requirement: str, k: NonNegativeInt = 0, **kwargs: Unpack[GenerateKwargs[List[str]]]
254
+ ) -> List[str]:
242
255
  """Asynchronously generates a list of strings based on a given requirement.
243
256
 
244
257
  Args:
@@ -258,7 +271,7 @@ class LLMUsage(ScopedConfig):
258
271
  **kwargs,
259
272
  )
260
273
 
261
- async def apathstr(self, requirement: str, **kwargs: Unpack[ChooseKwargs]) -> List[str]:
274
+ async def apathstr(self, requirement: str, **kwargs: Unpack[ChooseKwargs[List[str]]]) -> List[str]:
262
275
  """Asynchronously generates a list of strings based on a given requirement.
263
276
 
264
277
  Args:
@@ -276,7 +289,7 @@ class LLMUsage(ScopedConfig):
276
289
  **kwargs,
277
290
  )
278
291
 
279
- async def awhich_pathstr(self, requirement: str, **kwargs: Unpack[GenerateKwargs]) -> str:
292
+ async def awhich_pathstr(self, requirement: str, **kwargs: Unpack[GenerateKwargs[List[str]]]) -> str:
280
293
  """Asynchronously generates a single path string based on a given requirement.
281
294
 
282
295
  Args:
@@ -299,7 +312,7 @@ class LLMUsage(ScopedConfig):
299
312
  instruction: str,
300
313
  choices: List[T],
301
314
  k: NonNegativeInt = 0,
302
- **kwargs: Unpack[GenerateKwargs],
315
+ **kwargs: Unpack[GenerateKwargs[List[T]]],
303
316
  ) -> List[T]:
304
317
  """Asynchronously executes a multi-choice decision-making process, generating a prompt based on the instruction and options, and validates the returned selection results.
305
318
 
@@ -350,7 +363,7 @@ class LLMUsage(ScopedConfig):
350
363
  self,
351
364
  instruction: str,
352
365
  choices: List[T],
353
- **kwargs: Unpack[GenerateKwargs],
366
+ **kwargs: Unpack[GenerateKwargs[List[T]]],
354
367
  ) -> T:
355
368
  """Asynchronously picks a single choice from a list of options using AI validation.
356
369
 
@@ -379,7 +392,7 @@ class LLMUsage(ScopedConfig):
379
392
  prompt: str,
380
393
  affirm_case: str = "",
381
394
  deny_case: str = "",
382
- **kwargs: Unpack[GenerateKwargs],
395
+ **kwargs: Unpack[GenerateKwargs[bool]],
383
396
  ) -> bool:
384
397
  """Asynchronously judges a prompt using AI validation.
385
398
 
@@ -494,17 +507,13 @@ class ToolBoxUsage(LLMUsage):
494
507
  self,
495
508
  task: Task,
496
509
  system_message: str = "",
497
- k: NonNegativeInt = 0,
498
- max_validations: PositiveInt = 2,
499
- **kwargs: Unpack[LLMKwargs],
510
+ **kwargs: Unpack[ChooseKwargs[List[ToolBox]]],
500
511
  ) -> List[ToolBox]:
501
512
  """Asynchronously executes a multi-choice decision-making process to choose toolboxes.
502
513
 
503
514
  Args:
504
515
  task (Task): The task for which to choose toolboxes.
505
516
  system_message (str): Custom system-level prompt, defaults to an empty string.
506
- k (NonNegativeInt): The number of toolboxes to select, 0 means infinite. Defaults to 0.
507
- max_validations (PositiveInt): Maximum number of validation failures, default is 2.
508
517
  **kwargs (Unpack[LLMKwargs]): Additional keyword arguments for the LLM usage.
509
518
 
510
519
  Returns:
@@ -514,10 +523,8 @@ class ToolBoxUsage(LLMUsage):
514
523
  logger.warning("No toolboxes available.")
515
524
  return []
516
525
  return await self.achoose(
517
- instruction=task.briefing, # TODO write a template to build a more robust instruction
526
+ instruction=task.briefing,
518
527
  choices=list(self.toolboxes),
519
- k=k,
520
- max_validations=max_validations,
521
528
  system_message=system_message,
522
529
  **kwargs,
523
530
  )
@@ -526,19 +533,13 @@ class ToolBoxUsage(LLMUsage):
526
533
  self,
527
534
  task: Task,
528
535
  toolbox: ToolBox,
529
- system_message: str = "",
530
- k: NonNegativeInt = 0,
531
- max_validations: PositiveInt = 2,
532
- **kwargs: Unpack[LLMKwargs],
536
+ **kwargs: Unpack[ChooseKwargs[List[Tool]]],
533
537
  ) -> List[Tool]:
534
538
  """Asynchronously executes a multi-choice decision-making process to choose tools.
535
539
 
536
540
  Args:
537
541
  task (Task): The task for which to choose tools.
538
542
  toolbox (ToolBox): The toolbox from which to choose tools.
539
- system_message (str): Custom system-level prompt, defaults to an empty string.
540
- k (NonNegativeInt): The number of tools to select, 0 means infinite. Defaults to 0.
541
- max_validations (PositiveInt): Maximum number of validation failures, default is 2.
542
543
  **kwargs (Unpack[LLMKwargs]): Additional keyword arguments for the LLM usage.
543
544
 
544
545
  Returns:
@@ -548,11 +549,8 @@ class ToolBoxUsage(LLMUsage):
548
549
  logger.warning(f"No tools available in toolbox {toolbox.name}.")
549
550
  return []
550
551
  return await self.achoose(
551
- instruction=task.briefing, # TODO write a template to build a more robust instruction
552
+ instruction=task.briefing,
552
553
  choices=toolbox.tools,
553
- k=k,
554
- max_validations=max_validations,
555
- system_message=system_message,
556
554
  **kwargs,
557
555
  )
558
556
 
@@ -7,6 +7,7 @@ from fabricatio.fs import (
7
7
  delete_directory,
8
8
  delete_file,
9
9
  dump_text,
10
+ gather_files,
10
11
  move_file,
11
12
  safe_json_read,
12
13
  safe_text_read,
@@ -26,4 +27,5 @@ fs_toolbox = (
26
27
  .add_tool(absolute_path)
27
28
  .add_tool(safe_text_read)
28
29
  .add_tool(safe_json_read)
30
+ .add_tool(gather_files)
29
31
  )
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fabricatio
3
- Version: 0.2.5.dev1
3
+ Version: 0.2.5.dev3
4
4
  Classifier: License :: OSI Approved :: MIT License
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: Programming Language :: Python :: 3.12
@@ -9,7 +9,6 @@ Classifier: Framework :: AsyncIO
9
9
  Classifier: Framework :: Pydantic :: 2
10
10
  Classifier: Typing :: Typed
11
11
  Requires-Dist: appdirs>=1.4.4
12
- Requires-Dist: async-cache>=1.1.1
13
12
  Requires-Dist: asyncio>=3.4.3
14
13
  Requires-Dist: asyncstdlib>=3.13.0
15
14
  Requires-Dist: litellm>=1.60.0
@@ -1,41 +1,41 @@
1
- fabricatio-0.2.5.dev1.dist-info/METADATA,sha256=PsgnEb4yQ2DY_hhyF2y3h0smp-IZwa49GxJb0Mftekc,8623
2
- fabricatio-0.2.5.dev1.dist-info/WHEEL,sha256=RIvmwLDYujv60MYBx2jxyP4vdn1DD7X0kBgz1TQvZuc,108
3
- fabricatio-0.2.5.dev1.dist-info/licenses/LICENSE,sha256=yDZaTLnOi03bi3Dk6f5IjhLUc5old2yOsihHWU0z-i0,1067
1
+ fabricatio-0.2.5.dev3.dist-info/METADATA,sha256=MKx81GhYa4Kl5fyAn1CtYrdf_nWPZt-sq86I_iteWXE,8589
2
+ fabricatio-0.2.5.dev3.dist-info/WHEEL,sha256=RIvmwLDYujv60MYBx2jxyP4vdn1DD7X0kBgz1TQvZuc,108
3
+ fabricatio-0.2.5.dev3.dist-info/licenses/LICENSE,sha256=yDZaTLnOi03bi3Dk6f5IjhLUc5old2yOsihHWU0z-i0,1067
4
4
  fabricatio/decorators.py,sha256=cJHsxxbnMhc4SzPl4454CPLuDP3H0qbTrzV_U2rLPrs,6372
5
5
  fabricatio/core.py,sha256=MaEKZ6DDmbdScAY-7F1gwGA6fr7ADX6Mz5rNVi2msFA,6277
6
6
  fabricatio/models/generic.py,sha256=dP5rNf13Yo-Zy0WpmunsDYOxNbJF3RpFcVBTrYaHnvc,12197
7
7
  fabricatio/models/tool.py,sha256=m7gFo8nXywGj7J3zOfPC_wPUgcTY-76ZwAmHlQLWkb8,6836
8
- fabricatio/models/role.py,sha256=cmKhS_IVjvwkjusestEci_0F0hK0eCa_1Hl4U9vqhiY,1774
8
+ fabricatio/models/role.py,sha256=Xd-TYNefcY9FGeINAI8Q5sCu2pgBXl0l9XKxN0r4rZ0,1791
9
9
  fabricatio/models/extra.py,sha256=svUxjM9iPtXCpNJwxYdkvRtvORsze8Fcz4Oql-46huQ,7295
10
- fabricatio/models/kwargs_types.py,sha256=_nycS6qG1geLmVR5Rh29w7bsANbYyPoI5n77AYO4nMQ,1935
10
+ fabricatio/models/kwargs_types.py,sha256=3K7c72NYnqQ7aEs6tTninVb2670bNqiKdfUT7uzLjas,4769
11
11
  fabricatio/models/utils.py,sha256=vahILaesw50ofFft-wZ9kZ_Qogqi6vIOISWczvwVXxk,4311
12
- fabricatio/models/usages.py,sha256=bhRaAlqLSt7p3Khgot4uElo8C-hzVbwst3boeIIMpXo,26237
12
+ fabricatio/models/usages.py,sha256=TBADSlnY70ewfXri3FbIPaD_jzgZz4dwMNEMJtWirxw,25845
13
13
  fabricatio/models/events.py,sha256=sBCKeNoYc4TFDoke-jhFEyA11RcdGu-wdF5ynAuVOMM,3983
14
14
  fabricatio/models/task.py,sha256=BdBfCtxzgDzqHE0eP65liUGRmddAtKhim6optodzEcQ,10193
15
- fabricatio/models/action.py,sha256=JgCjyddvY-YYnfQPdBwe7i-r4CJNTkGSMnuUW8666HQ,6326
16
- fabricatio/toolboxes/fs.py,sha256=0Uxbxj0kPYQ7srtP5eL_O-e83DBpNwEiaNLDu8ZsOug,659
15
+ fabricatio/models/action.py,sha256=xAzNbkRMh8-6V-P9VwOgbc_hoFLcsXe7w0vcdSxmqhU,6285
16
+ fabricatio/toolboxes/fs.py,sha256=OQMdeokYxSNVrCZJAweJ0cYiK4k2QuEiNdIbS5IHIV8,705
17
17
  fabricatio/toolboxes/__init__.py,sha256=dYm_Gd8XolSU_h4wnkA09dlaLDK146eeFz0CUgPZ8_c,380
18
18
  fabricatio/toolboxes/arithmetic.py,sha256=sSTPkKI6-mb278DwQKFO9jKyzc9kCx45xNH7V6bGBpE,1307
19
19
  fabricatio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  fabricatio/fs/readers.py,sha256=JNjTaHpH0ljXxJ7SREJYL5gU8bbCe3lDEaVCmna1rww,1168
21
- fabricatio/fs/curd.py,sha256=DjaL8_lROZVcPghC0U1u7mklLWFxbO9Vz1LWqp6aLl0,4010
22
- fabricatio/fs/__init__.py,sha256=kfE2e_ijOQtDND_GUBGWDEwtgcP5pYAymCgT0H3qh6M,521
23
- fabricatio/config.py,sha256=niQ2_IfIQXc6JV4Ff7Z3uGn2SdCEmdGne1lozKikp00,13641
24
- fabricatio/journal.py,sha256=bzxZay48ZWI0VIkkDXm4Wc_Cc9lBQYa2VGx3Hxy_PtA,753
21
+ fabricatio/fs/curd.py,sha256=FuG75qco4dX8vhIK27gKz9rKUXbWHOFg5yK3nGLB25s,4469
22
+ fabricatio/fs/__init__.py,sha256=iNYphupcebrXEKLG2MgLliEUlh_G6xmupqfVrUwGT9E,559
23
+ fabricatio/config.py,sha256=tByDnt0HOthTOdEYK4KJwUqT74gJSVjUUxNOtc9Sa58,14422
24
+ fabricatio/journal.py,sha256=HbqgbSMckpr8vNxNAR1k4EbRtpzVZDnWzvu9at0hhrc,752
25
25
  fabricatio/__init__.py,sha256=kr86hyEDgUbxl1KmWTJqmW1R-aeC8Hd4KFp-2HFr0LM,1870
26
26
  fabricatio/actions/output.py,sha256=0sKfU8C9y326IcgZMLeEoZZH3iMpgFGOLGoi9wYZz1U,663
27
27
  fabricatio/actions/rag.py,sha256=tP1uKLq7mo19YhsJzFbGYryrcMx6xcvBc3n_Wzh0hjg,796
28
28
  fabricatio/actions/article.py,sha256=-WKVYu1HrQOL5nyBraCvRG2bfbkTa_ylH_PyFSI6iLs,2704
29
- fabricatio/_rust_instances.py,sha256=JAtO-vL8ihvduf1SHLNf0w7ZSVGCJeIv6zZ9Ekyy1hY,271
29
+ fabricatio/_rust_instances.py,sha256=CdvEQquLgXJ4slqYlqAYyBIzo3hiAmx1M98PIP2ajww,304
30
30
  fabricatio/workflows/articles.py,sha256=utvKDBFEJbcM76729-H2AvgMCNcsX1NquqMpHqGZq8E,565
31
31
  fabricatio/workflows/rag.py,sha256=uOZXprD479fUhLA6sYvEM8RWcVcUZXXtP0xRbTMPdHE,509
32
32
  fabricatio/parser.py,sha256=S-4p1mjvJZEgnQW6WKdkmE68MzqqWXGSiLbADdhE-W4,4791
33
33
  fabricatio/capabilities/rag.py,sha256=mGUWaVsLbA1vNe0LRdAOeUlR4WMc6mwuOQ0vhPG8m74,15181
34
- fabricatio/capabilities/rating.py,sha256=ZBlWbecHTAtRhO1beO4fWX3IfwjeyAYSvpXGIRhoGss,13384
35
- fabricatio/capabilities/review.py,sha256=rsUlKZzURibM33UxuqjgPgxlHcA1vEGvCb-sIeZO9Do,5725
36
- fabricatio/capabilities/propose.py,sha256=oW9QKpY2mDkVPEvgsgqxXxDR2ylVqN5TEL8E0Wh_vJI,1714
34
+ fabricatio/capabilities/rating.py,sha256=_F8-t60W4EFHW62gPOFgys4oqAoXAVk442oz91P0z0c,14044
35
+ fabricatio/capabilities/review.py,sha256=PoJZrPGq8FvqLjQELuWv1CCMcJMusuv6KZTl7Wv6_zE,9463
36
+ fabricatio/capabilities/propose.py,sha256=fuQzwx6OBymEbHbHDDPoT4sqFRso8u6Kk7NXKS5DFVc,1723
37
37
  fabricatio/capabilities/task.py,sha256=BISAFbMgBI4udW0otE3-iyq0RXc05YN_30N0yI5qLxQ,4504
38
- fabricatio/_rust.pyi,sha256=tKI4o5ZsxcW4k-O5etU5s60TzjRgJArYxR2YUk7sqkE,1980
39
- fabricatio/_rust.cpython-312-x86_64-linux-gnu.so,sha256=1ySWosE-ZFyYk7EHHNApJ54x4Q5QgUY4aRrb92LgyLQ,1684256
40
- fabricatio-0.2.5.dev1.data/scripts/tdown,sha256=EP2gMfsbKrPyWPCx4itYrQqbhVaVpbCxoufK3IbXrTs,4568208
41
- fabricatio-0.2.5.dev1.dist-info/RECORD,,
38
+ fabricatio/_rust.pyi,sha256=xXSaL7llihyFIyr9_k6e5RRJVNYk2jM-jrrheNvvaIA,3067
39
+ fabricatio/_rust.cpython-312-x86_64-linux-gnu.so,sha256=X-d8ziGuBqQEtJXheq6NTFAsxotGLiy2it6rteu9Cic,1898944
40
+ fabricatio-0.2.5.dev3.data/scripts/tdown,sha256=MsmVZJr1r5g1VXyayAS7DEtHgLj0O8a2YbGNf1u6SDw,4571832
41
+ fabricatio-0.2.5.dev3.dist-info/RECORD,,
Binary file