fabricatio 0.2.3.dev1__cp312-cp312-manylinux_2_34_x86_64.whl → 0.2.3.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/__init__.py CHANGED
@@ -1,5 +1,7 @@
1
1
  """Fabricatio is a Python library for building llm app using event-based agent structure."""
2
2
 
3
+ from importlib.util import find_spec
4
+
3
5
  from fabricatio._rust_instances import template_manager
4
6
  from fabricatio.core import env
5
7
  from fabricatio.fs import magika
@@ -35,3 +37,9 @@ __all__ = [
35
37
  "task_toolbox",
36
38
  "template_manager",
37
39
  ]
40
+
41
+
42
+ if find_spec("pymilvus"):
43
+ from fabricatio.capabilities.rag import Rag
44
+
45
+ __all__ += ["Rag"]
@@ -1,46 +1,225 @@
1
1
  """A module for the RAG (Retrieval Augmented Generation) model."""
2
2
 
3
- from typing import Any, Dict, List, Optional, Self, Union
3
+ from functools import lru_cache
4
+ from operator import itemgetter
5
+ from os import PathLike
6
+ from pathlib import Path
7
+ from typing import Any, Callable, Dict, List, Optional, Self, Union, Unpack
4
8
 
9
+ from fabricatio import template_manager
5
10
  from fabricatio.config import configs
11
+ from fabricatio.models.kwargs_types import LLMKwargs
12
+ from fabricatio.models.usages import LLMUsage
6
13
  from fabricatio.models.utils import MilvusData
14
+ from more_itertools.recipes import flatten
7
15
 
8
16
  try:
9
17
  from pymilvus import MilvusClient
10
18
  except ImportError as e:
11
19
  raise RuntimeError("pymilvus is not installed. Have you installed `fabricatio[rag]` instead of `fabricatio`") from e
12
- from pydantic import BaseModel, ConfigDict, PrivateAttr
20
+ from pydantic import Field, PrivateAttr
13
21
 
14
22
 
15
- class Rag(BaseModel):
23
+ @lru_cache(maxsize=None)
24
+ def create_client(
25
+ uri: Optional[str] = None, token: Optional[str] = None, timeout: Optional[float] = None
26
+ ) -> MilvusClient:
27
+ """Create a Milvus client."""
28
+ return MilvusClient(
29
+ uri=uri or configs.rag.milvus_uri.unicode_string(),
30
+ token=token or configs.rag.milvus_token.get_secret_value() if configs.rag.milvus_token else "",
31
+ timeout=timeout or configs.rag.milvus_timeout,
32
+ )
33
+
34
+
35
+ class Rag(LLMUsage):
16
36
  """A class representing the RAG (Retrieval Augmented Generation) model."""
17
37
 
18
- model_config = ConfigDict(use_attribute_docstrings=True)
38
+ milvus_uri: Optional[str] = Field(default=None, frozen=True)
39
+ """The URI of the Milvus server."""
40
+ milvus_token: Optional[str] = Field(default=None, frozen=True)
41
+ """The token for the Milvus server."""
42
+ milvus_timeout: Optional[float] = Field(default=None, frozen=True)
43
+ """The timeout for the Milvus server."""
44
+ target_collection: Optional[str] = Field(default=None)
45
+ """The name of the collection being viewed."""
19
46
 
20
- _client: MilvusClient = PrivateAttr(
21
- default=MilvusClient(
22
- uri=configs.rag.milvus_uri.unicode_string(),
23
- token=configs.rag.milvus_token.get_secret_value(),
24
- timeout=configs.rag.milvus_timeout,
25
- ),
26
- )
27
- _target_collection: Optional[str] = PrivateAttr(default=None)
47
+ _client: MilvusClient = PrivateAttr(None)
48
+ """The Milvus client used for the RAG model."""
28
49
 
29
50
  @property
30
51
  def client(self) -> MilvusClient:
31
- """The Milvus client."""
52
+ """Return the Milvus client."""
32
53
  return self._client
33
54
 
34
- def add_document[D: Union[Dict[str, Any] | MilvusData]](self, collection_name: str, data: D | List[D]) -> Self:
35
- """Adds a document to the specified collection.
55
+ def model_post_init(self, __context: Any) -> None:
56
+ """Initialize the RAG model by creating the collection if it does not exist."""
57
+ self._client = create_client(self.milvus_uri, self.milvus_token, self.milvus_timeout)
58
+ self.view(self.target_collection, create=True)
59
+
60
+ def view(self, collection_name: Optional[str], create: bool = False) -> Self:
61
+ """View the specified collection.
36
62
 
37
63
  Args:
38
64
  collection_name (str): The name of the collection.
39
- data (dict): The data to be added to the collection.
65
+ create (bool): Whether to create the collection if it does not exist.
66
+ """
67
+ if create and collection_name and not self._client.has_collection(collection_name):
68
+ self._client.create_collection(collection_name)
69
+
70
+ self.target_collection = collection_name
71
+ return self
72
+
73
+ def quit_viewing(self) -> Self:
74
+ """Quit the current view.
75
+
76
+ Returns:
77
+ Self: The current instance, allowing for method chaining.
78
+ """
79
+ return self.view(None)
80
+
81
+ @property
82
+ def safe_target_collection(self) -> str:
83
+ """Get the name of the collection being viewed, raise an error if not viewing any collection.
84
+
85
+ Returns:
86
+ str: The name of the collection being viewed.
87
+ """
88
+ if self.target_collection is None:
89
+ raise RuntimeError("No collection is being viewed. Have you called `self.view()`?")
90
+ return self.target_collection
91
+
92
+ def add_document[D: Union[Dict[str, Any], MilvusData]](
93
+ self, data: D | List[D], collection_name: Optional[str] = None
94
+ ) -> Self:
95
+ """Adds a document to the specified collection.
96
+
97
+ Args:
98
+ data (Union[Dict[str, Any], MilvusData] | List[Union[Dict[str, Any], MilvusData]]): The data to be added to the collection.
99
+ collection_name (Optional[str]): The name of the collection. If not provided, the currently viewed collection is used.
100
+
101
+ Returns:
102
+ Self: The current instance, allowing for method chaining.
40
103
  """
41
104
  if isinstance(data, MilvusData):
42
105
  data = data.prepare_insertion()
43
106
  if isinstance(data, list):
44
107
  data = [d.prepare_insertion() if isinstance(d, MilvusData) else d for d in data]
45
- self.client.insert(collection_name, data)
108
+ self._client.insert(collection_name or self.safe_target_collection, data)
46
109
  return self
110
+
111
+ def consume(
112
+ self, source: PathLike, reader: Callable[[PathLike], MilvusData], collection_name: Optional[str] = None
113
+ ) -> Self:
114
+ """Consume a file and add its content to the collection.
115
+
116
+ Args:
117
+ source (PathLike): The path to the file to be consumed.
118
+ reader (Callable[[PathLike], MilvusData]): The reader function to read the file.
119
+ collection_name (Optional[str]): The name of the collection. If not provided, the currently viewed collection is used.
120
+
121
+ Returns:
122
+ Self: The current instance, allowing for method chaining.
123
+ """
124
+ data = reader(Path(source))
125
+ self.add_document(data, collection_name or self.safe_target_collection)
126
+ return self
127
+
128
+ async def afetch_document(
129
+ self,
130
+ vecs: List[List[float]],
131
+ desired_fields: List[str] | str,
132
+ collection_name: Optional[str] = None,
133
+ result_per_query: int = 10,
134
+ ) -> List[Dict[str, Any]] | List[Any]:
135
+ """Fetch data from the collection.
136
+
137
+ Args:
138
+ vecs (List[List[float]]): The vectors to search for.
139
+ desired_fields (List[str] | str): The fields to retrieve.
140
+ collection_name (Optional[str]): The name of the collection. If not provided, the currently viewed collection is used.
141
+ result_per_query (int): The number of results to return per query.
142
+
143
+ Returns:
144
+ List[Dict[str, Any]] | List[Any]: The retrieved data.
145
+ """
146
+ # Step 1: Search for vectors
147
+ search_results = self._client.search(
148
+ collection_name or self.safe_target_collection,
149
+ vecs,
150
+ output_fields=desired_fields if isinstance(desired_fields, list) else [desired_fields],
151
+ limit=result_per_query,
152
+ )
153
+
154
+ # Step 2: Flatten the search results
155
+ flattened_results = flatten(search_results)
156
+
157
+ # Step 3: Sort by distance (descending)
158
+ sorted_results = sorted(flattened_results, key=itemgetter("distance"), reverse=True)
159
+
160
+ # Step 4: Extract the entities
161
+ resp = [result["entity"] for result in sorted_results]
162
+
163
+ if isinstance(desired_fields, list):
164
+ return resp
165
+ return [r.get(desired_fields) for r in resp]
166
+
167
+ async def aretrieve(
168
+ self,
169
+ query: List[str] | str,
170
+ collection_name: Optional[str] = None,
171
+ result_per_query: int = 10,
172
+ final_limit: int = 20,
173
+ ) -> List[str]:
174
+ """Retrieve data from the collection.
175
+
176
+ Args:
177
+ query (List[str] | str): The query to be used for retrieval.
178
+ collection_name (Optional[str]): The name of the collection. If not provided, the currently viewed collection is used.
179
+ result_per_query (int): The number of results to be returned per query.
180
+ final_limit (int): The final limit on the number of results to return.
181
+
182
+ Returns:
183
+ List[str]: A list of strings containing the retrieved data.
184
+ """
185
+ if isinstance(query, str):
186
+ query = [query]
187
+ return await self.afetch_document(
188
+ vecs=(await self.vectorize(query)),
189
+ desired_fields="text",
190
+ collection_name=collection_name,
191
+ result_per_query=result_per_query,
192
+ )[:final_limit]
193
+
194
+ async def aask_retrieved(
195
+ self,
196
+ question: str | List[str],
197
+ query: List[str] | str,
198
+ collection_name: Optional[str] = None,
199
+ result_per_query: int = 10,
200
+ final_limit: int = 20,
201
+ **kwargs: Unpack[LLMKwargs],
202
+ ) -> str:
203
+ """Asks a question by retrieving relevant documents based on the provided query.
204
+
205
+ This method performs document retrieval using the given query, then asks the
206
+ specified question using the retrieved documents as context.
207
+
208
+ Args:
209
+ question (str | List[str]): The question or list of questions to be asked.
210
+ query (List[str] | str): The query or list of queries used for document retrieval.
211
+ collection_name (Optional[str]): The name of the collection to retrieve documents from.
212
+ If not provided, the currently viewed collection is used.
213
+ result_per_query (int): The number of results to return per query. Default is 10.
214
+ final_limit (int): The maximum number of retrieved documents to consider. Default is 20.
215
+ **kwargs (Unpack[LLMKwargs]): Additional keyword arguments passed to the underlying `aask` method.
216
+
217
+ Returns:
218
+ str: A string response generated after asking with the context of retrieved documents.
219
+ """
220
+ docs = await self.aretrieve(query, collection_name, result_per_query, final_limit)
221
+ return await self.aask(
222
+ question,
223
+ template_manager.render_template(configs.templates.retrieved_display_template, {"docs": docs}),
224
+ **kwargs,
225
+ )
fabricatio/config.py CHANGED
@@ -176,6 +176,9 @@ class TemplateConfig(BaseModel):
176
176
  draft_rating_weights_klee_template: str = Field(default="draft_rating_weights_klee")
177
177
  """The name of the draft rating weights klee template which will be used to draft rating weights with Klee method."""
178
178
 
179
+ retrieved_display_template: str = Field(default="retrieved_display")
180
+ """The name of the retrieved display template which will be used to display retrieved documents."""
181
+
179
182
 
180
183
  class MagikaConfig(BaseModel):
181
184
  """Magika configuration class."""
fabricatio/models/task.py CHANGED
@@ -46,19 +46,19 @@ class Task[T](WithBriefing, WithJsonExample, WithDependency):
46
46
  """
47
47
 
48
48
  name: str = Field(...)
49
- """The name of the task, which should be a concise and descriptive name."""
49
+ """The name of the task, which should be concise and descriptive."""
50
50
 
51
51
  description: str = Field(default="")
52
- """The description of the task, which should provide every details and noting about the task if provided, obeying the CEFR level rule and 5W1H rule."""
52
+ """A detailed explanation of the task that includes all necessary information. Should be clear and answer what, why, when, where, who, and how questions."""
53
53
 
54
- goal: List[str] = Field(default=[])
55
- """The goal of the task, a list of strings. The goal should be a concise and clear statement of what the task is intended to achieve, goal SHALL NOT be too broad or too narrow."""
54
+ goals: List[str] = Field(default=[])
55
+ """A list of objectives that the task aims to accomplish. Each goal should be clear and specific. Complex tasks should be broken into multiple smaller goals."""
56
56
 
57
57
  namespace: List[str] = Field(default_factory=list)
58
- """The namespace of the task, a list of namespace segment, as string, if it is not directly given out, it SHALL just be a empty list meaning `NOT ASSIGNED`"""
58
+ """A list of string segments that identify the task's location in the system. If not specified, defaults to an empty list."""
59
59
 
60
60
  dependencies: List[str] = Field(default_factory=list)
61
- """A list of file paths, These file are needed to read or write to meet a specific requirement of this task, if it is not directly given out, it SHALL just be a empty list meaning `NOT ASSIGNED`"""
61
+ """A list of file paths that are needed (either reading or writing) to complete this task. If not specified, defaults to an empty list."""
62
62
 
63
63
  _output: Queue[T | None] = PrivateAttr(default_factory=Queue)
64
64
  """The output queue of the task."""
@@ -113,7 +113,7 @@ class Task[T](WithBriefing, WithJsonExample, WithDependency):
113
113
  Returns:
114
114
  Task: A new instance of the `Task` class.
115
115
  """
116
- return cls(name=name, goal=goal, description=description)
116
+ return cls(name=name, goals=goal, description=description)
117
117
 
118
118
  def update_task(self, goal: Optional[List[str] | str] = None, description: Optional[str] = None) -> Self:
119
119
  """Update the goal and description of the task.
@@ -126,7 +126,7 @@ class Task[T](WithBriefing, WithJsonExample, WithDependency):
126
126
  Task: The updated instance of the `Task` class.
127
127
  """
128
128
  if goal:
129
- self.goal = goal if isinstance(goal, list) else [goal]
129
+ self.goals = goal if isinstance(goal, list) else [goal]
130
130
  if description:
131
131
  self.description = description
132
132
  return self
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fabricatio
3
- Version: 0.2.3.dev1
3
+ Version: 0.2.3.dev3
4
4
  Classifier: License :: OSI Approved :: MIT License
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: Programming Language :: Python :: 3.12
@@ -98,32 +98,32 @@ from fabricatio import Action, Role, Task, logger
98
98
 
99
99
 
100
100
  class Hello(Action):
101
- """Action that says hello."""
101
+ """Action that says hello."""
102
102
 
103
- name: str = "hello"
104
- output_key: str = "task_output"
103
+ name: str = "hello"
104
+ output_key: str = "task_output"
105
105
 
106
- async def _execute(self, task_input: Task[str], **_) -> Any:
107
- ret = "Hello fabricatio!"
108
- logger.info("executing talk action")
109
- return ret
106
+ async def _execute(self, task_input: Task[str], **_) -> Any:
107
+ ret = "Hello fabricatio!"
108
+ logger.info("executing talk action")
109
+ return ret
110
110
 
111
111
 
112
112
  async def main() -> None:
113
- """Main function."""
114
- role = Role(
115
- name="talker",
116
- description="talker role",
117
- registry={Task.pending_label: WorkFlow(name="talk", steps=(Hello,))}
118
- )
113
+ """Main function."""
114
+ role = Role(
115
+ name="talker",
116
+ description="talker role",
117
+ registry={Task.pending_label: WorkFlow(name="talk", steps=(Hello,))}
118
+ )
119
119
 
120
- task = Task(name="say hello", goal="say hello", description="say hello to the world")
121
- result = await task.delegate()
122
- logger.success(f"Result: {result}")
120
+ task = Task(name="say hello", goals="say hello", description="say hello to the world")
121
+ result = await task.delegate()
122
+ logger.success(f"Result: {result}")
123
123
 
124
124
 
125
125
  if __name__ == "__main__":
126
- asyncio.run(main())
126
+ asyncio.run(main())
127
127
  ```
128
128
 
129
129
  #### Writing and Dumping Code
@@ -311,17 +311,18 @@ from fabricatio.models.task import Task
311
311
 
312
312
  toolbox_usage = ToolBoxUsage()
313
313
 
314
+
314
315
  async def handle_security_vulnerabilities():
315
- task = Task(
316
- name="Security Check",
317
- goal=["Identify security vulnerabilities"],
318
- description="Perform a thorough security review on the project.",
319
- dependencies=["./src/main.py"]
320
- )
321
-
322
- vulnerabilities = await toolbox_usage.gather_tools_fine_grind(task)
323
- for vulnerability in vulnerabilities:
324
- print(f"Found vulnerability: {vulnerability.name}")
316
+ task = Task(
317
+ name="Security Check",
318
+ goals=["Identify security vulnerabilities"],
319
+ description="Perform a thorough security review on the project.",
320
+ dependencies=["./src/main.py"]
321
+ )
322
+
323
+ vulnerabilities = await toolbox_usage.gather_tools_fine_grind(task)
324
+ for vulnerability in vulnerabilities:
325
+ print(f"Found vulnerability: {vulnerability.name}")
325
326
  ```
326
327
 
327
328
  #### Managing CTF Challenges
@@ -334,19 +335,22 @@ from fabricatio.models.task import Task
334
335
 
335
336
  toolbox_usage = ToolBoxUsage()
336
337
 
338
+
337
339
  async def solve_ctf_challenge(challenge_name: str, challenge_description: str, files: list[str]):
338
- task = Task(
339
- name=challenge_name,
340
- goal=[f"Solve {challenge_name} challenge"],
341
- description=challenge_description,
342
- dependencies=files
343
- )
344
-
345
- solution = await toolbox_usage.gather_tools_fine_grind(task)
346
- print(f"Challenge Solved: {solution}")
340
+ task = Task(
341
+ name=challenge_name,
342
+ goals=[f"Solve {challenge_name} challenge"],
343
+ description=challenge_description,
344
+ dependencies=files
345
+ )
346
+
347
+ solution = await toolbox_usage.gather_tools_fine_grind(task)
348
+ print(f"Challenge Solved: {solution}")
349
+
347
350
 
348
351
  if __name__ == "__main__":
349
- asyncio.run(solve_ctf_challenge("Binary Exploitation", "CTF Binary Exploitation Challenge", ["./challenges/binary_exploit"]))
352
+ asyncio.run(
353
+ solve_ctf_challenge("Binary Exploitation", "CTF Binary Exploitation Challenge", ["./challenges/binary_exploit"]))
350
354
  ```
351
355
 
352
356
  ### Configuration
@@ -1,6 +1,6 @@
1
- fabricatio-0.2.3.dev1.dist-info/METADATA,sha256=0NOXlwnHxtpH1XjaFx4xx_1wSQGLOX4XzsodmXBBTgk,11960
2
- fabricatio-0.2.3.dev1.dist-info/WHEEL,sha256=RIvmwLDYujv60MYBx2jxyP4vdn1DD7X0kBgz1TQvZuc,108
3
- fabricatio-0.2.3.dev1.dist-info/licenses/LICENSE,sha256=yDZaTLnOi03bi3Dk6f5IjhLUc5old2yOsihHWU0z-i0,1067
1
+ fabricatio-0.2.3.dev3.dist-info/METADATA,sha256=-3639SKLzCTOvpu4nz4VKm00nP4zt-Ot3pz4_e6PG7o,11913
2
+ fabricatio-0.2.3.dev3.dist-info/WHEEL,sha256=RIvmwLDYujv60MYBx2jxyP4vdn1DD7X0kBgz1TQvZuc,108
3
+ fabricatio-0.2.3.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=4j6DRNkHLNhx8U6aijf0Cz9HSahtEPQBh22i6d_PGTs,4981
@@ -10,7 +10,7 @@ fabricatio/models/kwargs_types.py,sha256=litzaTVzzLjOpddAVdLfsuys_rFoqTyv0etCh9y
10
10
  fabricatio/models/utils.py,sha256=ZmVHsfMbIWLGQoZSJLYInDZkQvmpmS5RGBTkJXveNHc,3825
11
11
  fabricatio/models/usages.py,sha256=0pyQBahL2lp_Bb_nSyxrW44cm3Me1Btxk3c7YVK32WI,27554
12
12
  fabricatio/models/events.py,sha256=TkMSJYSzRgurbfY2knWIc8gYw7rmaWqB7KeYzy5jeWU,2637
13
- fabricatio/models/task.py,sha256=tPeX9i-dPpxQfrkX7xR2ESFlIXUTg2z-TqOVx5_qUCU,11198
13
+ fabricatio/models/task.py,sha256=U63ULoPkOXx9UyqYqdGmALBGxn9lAidXbSxIZZXlbVM,11088
14
14
  fabricatio/models/action.py,sha256=006Jjfr9p-EBErboAn29yvyolIGi5mbJ_DA5og0Uh64,5780
15
15
  fabricatio/toolboxes/fs.py,sha256=oZjGOmtN8ZbkMXxCMatqvdPavVXyQ87AEDc1lx9jimY,483
16
16
  fabricatio/toolboxes/__init__.py,sha256=iEBsH0aRPLccIe6eyZ6iH5GdK8yYNQTnCwLzw4pWXAA,465
@@ -20,18 +20,18 @@ fabricatio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  fabricatio/fs/readers.py,sha256=lqMrM5Nt3l6QJmPDoBno2PSaN2BbFwfUjBqaghrbK3A,1002
21
21
  fabricatio/fs/curd.py,sha256=g74Pc2WPSkPlCXX0cWj2jyiDYTfkLwpwM480eyCkmc8,3851
22
22
  fabricatio/fs/__init__.py,sha256=bYE9r8uR0dtknzbg_YaGv_6Wwa27ntkQt0Tl7Kb3HFI,117
23
- fabricatio/config.py,sha256=7lmhzEkKi8eSiVBaHjjV0cEyGCanAUmFXYOrOGn7Y7c,11742
23
+ fabricatio/config.py,sha256=X4oDFVKPycSGuFYrn9cVURalU3fmUSRXBIF7bfpONZo,11920
24
24
  fabricatio/journal.py,sha256=bzxZay48ZWI0VIkkDXm4Wc_Cc9lBQYa2VGx3Hxy_PtA,753
25
- fabricatio/__init__.py,sha256=h0FgwSAdI2yhxYiuQi46uFvzqkK5LfJLt5XsHZ9rWIo,1063
25
+ fabricatio/__init__.py,sha256=DNPOP3s4_5KswbEyFojSEjMp3JuckcsGz8OVGfRaUhY,1201
26
26
  fabricatio/actions/communication.py,sha256=MrL_revv1zm1VXqjDMKZkg4PHmyMxYThAmmw2wF791k,414
27
27
  fabricatio/actions/transmission.py,sha256=WM-kssiqzTLZuZSiqbRvBaC2qynd9kjrKXya4f9Zcb0,839
28
28
  fabricatio/actions/__init__.py,sha256=eLa_5ACZ-FqdrLtOfCHk5nQBxzhIs1kgMIXWmkm2P8Y,110
29
29
  fabricatio/_rust_instances.py,sha256=JAtO-vL8ihvduf1SHLNf0w7ZSVGCJeIv6zZ9Ekyy1hY,271
30
30
  fabricatio/parser.py,sha256=Q4laV79Svggl09UKa3lAw6NYPuDz1sP2F-6U4tsSvQw,3429
31
- fabricatio/capabilities/rag.py,sha256=EN1plVCKUPylbe2rilvCBNmf0F13zFmOck9vLUkz3lQ,1671
31
+ fabricatio/capabilities/rag.py,sha256=prL7RL3RtB64lXj0q8TUyksZ39MrEXnWXDgaACQryRQ,9259
32
32
  fabricatio/capabilities/rating.py,sha256=KLJlaufG74lHJ5hHI_tjhQgjWjHhO_38Q1ILW2cY9fA,14552
33
33
  fabricatio/capabilities/task.py,sha256=UnkeON3VCADXUBtUmQbMwl9TEwK0yQSED3EglqMMHQ4,5196
34
34
  fabricatio/_rust.pyi,sha256=clhcURuiB9zlFo4m3VyoWQ8Xs4tvg6KNHXpF-ok9h4o,1703
35
- fabricatio/_rust.cpython-312-x86_64-linux-gnu.so,sha256=RwfP3a0Y0W82yUIHmH-SuNI6ZD_4X1dmu_QoREHvhnw,1336568
36
- fabricatio-0.2.3.dev1.data/scripts/tdown,sha256=sYeLflc31k_aVFo7_y-QEBe3yfz6uN0PqJ0cLpyMkOU,4569184
37
- fabricatio-0.2.3.dev1.dist-info/RECORD,,
35
+ fabricatio/_rust.cpython-312-x86_64-linux-gnu.so,sha256=8sQa5DyKEnGWd4_JacuJksUI8m0pjyGKoF66BzOXmNA,1336728
36
+ fabricatio-0.2.3.dev3.data/scripts/tdown,sha256=KnHYVZuHJisg6DR_zhOUGujgx25BZ9Jsw3HykXNrOlM,4578648
37
+ fabricatio-0.2.3.dev3.dist-info/RECORD,,
Binary file