fabricatio 0.3.14.dev4__cp313-cp313-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 +29 -0
- fabricatio/actions/__init__.py +1 -0
- fabricatio/actions/article.py +319 -0
- fabricatio/actions/article_rag.py +416 -0
- fabricatio/actions/fs.py +25 -0
- fabricatio/actions/output.py +248 -0
- fabricatio/actions/rag.py +96 -0
- fabricatio/actions/rules.py +83 -0
- fabricatio/capabilities/__init__.py +1 -0
- fabricatio/capabilities/advanced_judge.py +20 -0
- fabricatio/capabilities/advanced_rag.py +61 -0
- fabricatio/capabilities/censor.py +105 -0
- fabricatio/capabilities/check.py +212 -0
- fabricatio/capabilities/correct.py +228 -0
- fabricatio/capabilities/extract.py +74 -0
- fabricatio/capabilities/persist.py +103 -0
- fabricatio/capabilities/propose.py +65 -0
- fabricatio/capabilities/rag.py +263 -0
- fabricatio/capabilities/rating.py +404 -0
- fabricatio/capabilities/review.py +114 -0
- fabricatio/capabilities/task.py +113 -0
- fabricatio/decorators.py +251 -0
- fabricatio/emitter.py +177 -0
- fabricatio/fs/__init__.py +35 -0
- fabricatio/fs/curd.py +153 -0
- fabricatio/fs/readers.py +61 -0
- fabricatio/journal.py +12 -0
- fabricatio/models/action.py +263 -0
- fabricatio/models/adv_kwargs_types.py +63 -0
- fabricatio/models/extra/__init__.py +1 -0
- fabricatio/models/extra/advanced_judge.py +32 -0
- fabricatio/models/extra/aricle_rag.py +284 -0
- fabricatio/models/extra/article_base.py +422 -0
- fabricatio/models/extra/article_essence.py +101 -0
- fabricatio/models/extra/article_main.py +285 -0
- fabricatio/models/extra/article_outline.py +46 -0
- fabricatio/models/extra/article_proposal.py +52 -0
- fabricatio/models/extra/patches.py +20 -0
- fabricatio/models/extra/problem.py +165 -0
- fabricatio/models/extra/rag.py +98 -0
- fabricatio/models/extra/rule.py +52 -0
- fabricatio/models/generic.py +812 -0
- fabricatio/models/kwargs_types.py +121 -0
- fabricatio/models/role.py +95 -0
- fabricatio/models/task.py +310 -0
- fabricatio/models/tool.py +328 -0
- fabricatio/models/usages.py +791 -0
- fabricatio/parser.py +114 -0
- fabricatio/py.typed +0 -0
- fabricatio/rust.cpython-313-x86_64-linux-gnu.so +0 -0
- fabricatio/rust.pyi +846 -0
- fabricatio/toolboxes/__init__.py +15 -0
- fabricatio/toolboxes/arithmetic.py +62 -0
- fabricatio/toolboxes/fs.py +31 -0
- fabricatio/utils.py +156 -0
- fabricatio/workflows/__init__.py +1 -0
- fabricatio/workflows/articles.py +24 -0
- fabricatio/workflows/rag.py +11 -0
- fabricatio-0.3.14.dev4.data/scripts/tdown +0 -0
- fabricatio-0.3.14.dev4.data/scripts/ttm +0 -0
- fabricatio-0.3.14.dev4.dist-info/METADATA +188 -0
- fabricatio-0.3.14.dev4.dist-info/RECORD +64 -0
- fabricatio-0.3.14.dev4.dist-info/WHEEL +4 -0
- fabricatio-0.3.14.dev4.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,328 @@
|
|
1
|
+
"""A module for defining tools and toolboxes.
|
2
|
+
|
3
|
+
This module provides classes for defining tools and toolboxes, which can be used to manage and execute callable functions
|
4
|
+
with additional functionalities such as logging, execution info, and briefing.
|
5
|
+
"""
|
6
|
+
from importlib.machinery import ModuleSpec
|
7
|
+
from importlib.util import module_from_spec
|
8
|
+
from inspect import iscoroutinefunction, signature
|
9
|
+
from types import CodeType, ModuleType
|
10
|
+
from typing import Any, Callable, Dict, List, Optional, Self, cast, overload
|
11
|
+
|
12
|
+
from fabricatio.rust import CONFIG
|
13
|
+
from pydantic import Field
|
14
|
+
|
15
|
+
from fabricatio.decorators import logging_execution_info, use_temp_module
|
16
|
+
from fabricatio.journal import logger
|
17
|
+
from fabricatio.models.generic import Base, WithBriefing
|
18
|
+
|
19
|
+
|
20
|
+
class Tool[**P, R](WithBriefing):
|
21
|
+
"""A class representing a tool with a callable source function.
|
22
|
+
|
23
|
+
This class encapsulates a callable function (source) and provides methods to invoke it, log its execution, and generate
|
24
|
+
a brief description (briefing) of the tool.
|
25
|
+
|
26
|
+
Attributes:
|
27
|
+
name (str): The name of the tool.
|
28
|
+
description (str): The description of the tool.
|
29
|
+
source (Callable[P, R]): The source function of the tool.
|
30
|
+
"""
|
31
|
+
|
32
|
+
name: str = Field(default="")
|
33
|
+
"""The name of the tool."""
|
34
|
+
|
35
|
+
description: str = Field(default="")
|
36
|
+
"""The description of the tool."""
|
37
|
+
|
38
|
+
source: Callable[P, R]
|
39
|
+
"""The source function of the tool."""
|
40
|
+
|
41
|
+
def model_post_init(self, __context: Any) -> None:
|
42
|
+
"""Initialize the tool with a name and a source function.
|
43
|
+
|
44
|
+
This method sets the tool's name and description based on the source function's name and docstring.
|
45
|
+
|
46
|
+
Args:
|
47
|
+
__context (Any): Context passed during model initialization.
|
48
|
+
|
49
|
+
Raises:
|
50
|
+
RuntimeError: If the tool does not have a source function.
|
51
|
+
"""
|
52
|
+
self.name = self.name or self.source.__name__
|
53
|
+
|
54
|
+
if not self.name:
|
55
|
+
raise RuntimeError("The tool must have a source function.")
|
56
|
+
|
57
|
+
self.description = self.description or self.source.__doc__ or ""
|
58
|
+
self.description = self.description.strip()
|
59
|
+
|
60
|
+
def invoke(self, *args: P.args, **kwargs: P.kwargs) -> R:
|
61
|
+
"""Invoke the tool's source function with the provided arguments.
|
62
|
+
|
63
|
+
This method logs the invocation of the tool and then calls the source function with the given arguments.
|
64
|
+
|
65
|
+
Args:
|
66
|
+
*args (P.args): Positional arguments to be passed to the source function.
|
67
|
+
**kwargs (P.kwargs): Keyword arguments to be passed to the source function.
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
R: The result of the source function.
|
71
|
+
"""
|
72
|
+
logger.info(f"Invoking tool: {self.name}")
|
73
|
+
return self.source(*args, **kwargs)
|
74
|
+
|
75
|
+
@property
|
76
|
+
def briefing(self) -> str:
|
77
|
+
"""Return a brief description of the tool.
|
78
|
+
|
79
|
+
This method generates a brief description of the tool, including its name, signature, and description.
|
80
|
+
|
81
|
+
Returns:
|
82
|
+
str: A brief description of the tool.
|
83
|
+
"""
|
84
|
+
# 获取源函数的返回类型
|
85
|
+
|
86
|
+
return f"{'async ' if iscoroutinefunction(self.source) else ''}def {self.name}{signature(self.source)}\n{_desc_wrapper(self.description)}"
|
87
|
+
|
88
|
+
|
89
|
+
def _desc_wrapper(desc: str) -> str:
|
90
|
+
lines = desc.split("\n")
|
91
|
+
lines_indent = [f" {line}" for line in ['"""', *lines, '"""']]
|
92
|
+
return "\n".join(lines_indent)
|
93
|
+
|
94
|
+
|
95
|
+
class ToolBox(WithBriefing):
|
96
|
+
"""A class representing a collection of tools.
|
97
|
+
|
98
|
+
This class manages a list of tools and provides methods to add tools, retrieve tools by name, and generate a brief
|
99
|
+
description (briefing) of the toolbox.
|
100
|
+
|
101
|
+
Attributes:
|
102
|
+
description (str): The description of the toolbox.
|
103
|
+
tools (List[Tool]): A list of tools in the toolbox.
|
104
|
+
"""
|
105
|
+
|
106
|
+
description: str = ""
|
107
|
+
"""The description of the toolbox."""
|
108
|
+
|
109
|
+
tools: List[Tool] = Field(default_factory=list, frozen=True)
|
110
|
+
"""A list of tools in the toolbox."""
|
111
|
+
|
112
|
+
def collect_tool[**P, R](self, func: Callable[P, R]) -> Callable[P, R]:
|
113
|
+
"""Add a callable function to the toolbox as a tool.
|
114
|
+
|
115
|
+
This method wraps the function with logging execution info and adds it to the toolbox.
|
116
|
+
|
117
|
+
Args:
|
118
|
+
func (Callable[P, R]): The function to be added as a tool.
|
119
|
+
|
120
|
+
Returns:
|
121
|
+
Callable[P, R]: The added function.
|
122
|
+
"""
|
123
|
+
self.tools.append(Tool(source=func))
|
124
|
+
return func
|
125
|
+
|
126
|
+
def add_tool[**P, R](self, func: Callable[P, R]) -> Self:
|
127
|
+
"""Add a callable function to the toolbox as a tool.
|
128
|
+
|
129
|
+
This method wraps the function with logging execution info and adds it to the toolbox.
|
130
|
+
|
131
|
+
Args:
|
132
|
+
func (Callable): The function to be added as a tool.
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
Self: The current instance of the toolbox.
|
136
|
+
"""
|
137
|
+
self.collect_tool(logging_execution_info(func))
|
138
|
+
return self
|
139
|
+
|
140
|
+
@property
|
141
|
+
def briefing(self) -> str:
|
142
|
+
"""Return a brief description of the toolbox.
|
143
|
+
|
144
|
+
This method generates a brief description of the toolbox, including its name, description, and a list of tools.
|
145
|
+
|
146
|
+
Returns:
|
147
|
+
str: A brief description of the toolbox.
|
148
|
+
"""
|
149
|
+
list_out = "\n\n".join([f"{tool.briefing}" for tool in self.tools])
|
150
|
+
toc = f"## {self.name}: {self.description}\n## {len(self.tools)} tools available:"
|
151
|
+
return f"{toc}\n\n{list_out}"
|
152
|
+
|
153
|
+
def get[**P, R](self, name: str) -> Tool[P, R]:
|
154
|
+
"""Invoke a tool by name with the provided arguments.
|
155
|
+
|
156
|
+
This method retrieves a tool by its name from the toolbox.
|
157
|
+
|
158
|
+
Args:
|
159
|
+
name (str): The name of the tool to invoke.
|
160
|
+
|
161
|
+
Returns:
|
162
|
+
Tool: The tool instance with the specified name.
|
163
|
+
|
164
|
+
Raises:
|
165
|
+
ValueError: If no tool with the specified name is found.
|
166
|
+
"""
|
167
|
+
tool = next((tool for tool in self.tools if tool.name == name), None)
|
168
|
+
if tool is None:
|
169
|
+
err = f"No tool with the name {name} found in the toolbox."
|
170
|
+
logger.error(err)
|
171
|
+
raise ValueError(err)
|
172
|
+
|
173
|
+
return tool
|
174
|
+
|
175
|
+
def __hash__(self) -> int:
|
176
|
+
"""Return a hash of the toolbox based on its briefing.
|
177
|
+
|
178
|
+
Returns:
|
179
|
+
int: A hash value based on the toolbox's briefing.
|
180
|
+
"""
|
181
|
+
return hash(self.briefing)
|
182
|
+
|
183
|
+
|
184
|
+
class ToolExecutor(Base):
|
185
|
+
"""A class representing a tool executor with a sequence of tools to execute.
|
186
|
+
|
187
|
+
This class manages a sequence of tools and provides methods to inject tools and data into a module, execute the tools,
|
188
|
+
and retrieve specific outputs.
|
189
|
+
|
190
|
+
Attributes:
|
191
|
+
candidates (List[Tool]): The sequence of tools to execute.
|
192
|
+
data (Dict[str, Any]): The data that could be used when invoking the tools.
|
193
|
+
"""
|
194
|
+
|
195
|
+
candidates: List[Tool] = Field(default_factory=list, frozen=True)
|
196
|
+
"""The sequence of tools to execute."""
|
197
|
+
|
198
|
+
data: Dict[str, Any] = Field(default_factory=dict)
|
199
|
+
"""The data that could be used when invoking the tools."""
|
200
|
+
|
201
|
+
def inject_tools[M: ModuleType](self, module: Optional[M] = None) -> M:
|
202
|
+
"""Inject the tools into the provided module or default.
|
203
|
+
|
204
|
+
This method injects the tools into the provided module or creates a new module if none is provided.
|
205
|
+
|
206
|
+
Args:
|
207
|
+
module (Optional[M]): The module to inject tools into. If None, a new module is created.
|
208
|
+
|
209
|
+
Returns:
|
210
|
+
M: The module with injected tools.
|
211
|
+
"""
|
212
|
+
module = module or cast(
|
213
|
+
"M", module_from_spec(spec=ModuleSpec(name=CONFIG.toolbox.tool_module_name, loader=None))
|
214
|
+
)
|
215
|
+
for tool in self.candidates:
|
216
|
+
logger.debug(f"Injecting tool: {tool.name}")
|
217
|
+
setattr(module, tool.name, tool.invoke)
|
218
|
+
return module
|
219
|
+
|
220
|
+
def inject_data[M: ModuleType](self, module: Optional[M] = None) -> M:
|
221
|
+
"""Inject the data into the provided module or default.
|
222
|
+
|
223
|
+
This method injects the data into the provided module or creates a new module if none is provided.
|
224
|
+
|
225
|
+
Args:
|
226
|
+
module (Optional[M]): The module to inject data into. If None, a new module is created.
|
227
|
+
|
228
|
+
Returns:
|
229
|
+
M: The module with injected data.
|
230
|
+
"""
|
231
|
+
module = module or cast(
|
232
|
+
"M", module_from_spec(spec=ModuleSpec(name=CONFIG.toolbox.data_module_name, loader=None))
|
233
|
+
)
|
234
|
+
for key, value in self.data.items():
|
235
|
+
logger.debug(f"Injecting data: {key}")
|
236
|
+
setattr(module, key, value)
|
237
|
+
return module
|
238
|
+
|
239
|
+
def execute[C: Dict[str, Any]](self, source: CodeType, cxt: Optional[C] = None) -> C:
|
240
|
+
"""Execute the sequence of tools with the provided context.
|
241
|
+
|
242
|
+
This method executes the tools in the sequence with the provided context.
|
243
|
+
|
244
|
+
Args:
|
245
|
+
source (CodeType): The source code to execute.
|
246
|
+
cxt (Optional[C]): The context to execute the tools with. If None, an empty dictionary is used.
|
247
|
+
|
248
|
+
Returns:
|
249
|
+
C: The context after executing the tools.
|
250
|
+
"""
|
251
|
+
cxt = cxt or {}
|
252
|
+
|
253
|
+
@use_temp_module([self.inject_data(), self.inject_tools()])
|
254
|
+
def _exec() -> None:
|
255
|
+
exec(source, cxt) # noqa: S102
|
256
|
+
|
257
|
+
_exec()
|
258
|
+
return cxt
|
259
|
+
|
260
|
+
@overload
|
261
|
+
def take[C: Dict[str, Any]](self, keys: List[str], source: CodeType, cxt: Optional[C] = None) -> C:
|
262
|
+
"""Check the output of the tools with the provided context.
|
263
|
+
|
264
|
+
This method executes the tools and retrieves specific keys from the context.
|
265
|
+
|
266
|
+
Args:
|
267
|
+
keys (List[str]): The keys to retrieve from the context.
|
268
|
+
source (CodeType): The source code to execute.
|
269
|
+
cxt (Optional[C]): The context to execute the tools with. If None, an empty dictionary is used.
|
270
|
+
|
271
|
+
Returns:
|
272
|
+
C: A dictionary containing the retrieved keys and their values.
|
273
|
+
"""
|
274
|
+
...
|
275
|
+
|
276
|
+
@overload
|
277
|
+
def take[C: Dict[str, Any]](self, keys: str, source: CodeType, cxt: Optional[C] = None) -> Any:
|
278
|
+
"""Check the output of the tools with the provided context.
|
279
|
+
|
280
|
+
This method executes the tools and retrieves a specific key from the context.
|
281
|
+
|
282
|
+
Args:
|
283
|
+
keys (str): The key to retrieve from the context.
|
284
|
+
source (CodeType): The source code to execute.
|
285
|
+
cxt (Optional[C]): The context to execute the tools with. If None, an empty dictionary is used.
|
286
|
+
|
287
|
+
Returns:
|
288
|
+
Any: The value of the retrieved key.
|
289
|
+
"""
|
290
|
+
...
|
291
|
+
|
292
|
+
def take[C: Dict[str, Any]](self, keys: List[str] | str, source: CodeType, cxt: Optional[C] = None) -> C | Any:
|
293
|
+
"""Check the output of the tools with the provided context.
|
294
|
+
|
295
|
+
This method executes the tools and retrieves specific keys or a specific key from the context.
|
296
|
+
|
297
|
+
Args:
|
298
|
+
keys (List[str] | str): The keys to retrieve from the context. Can be a single key or a list of keys.
|
299
|
+
source (CodeType): The source code to execute.
|
300
|
+
cxt (Optional[C]): The context to execute the tools with. If None, an empty dictionary is used.
|
301
|
+
|
302
|
+
Returns:
|
303
|
+
C | Any: A dictionary containing the retrieved keys and their values, or the value of the retrieved key.
|
304
|
+
"""
|
305
|
+
cxt = self.execute(source, cxt)
|
306
|
+
if isinstance(keys, str):
|
307
|
+
return cxt[keys]
|
308
|
+
return {key: cxt[key] for key in keys}
|
309
|
+
|
310
|
+
@classmethod
|
311
|
+
def from_recipe(cls, recipe: List[str], toolboxes: List[ToolBox]) -> Self:
|
312
|
+
"""Create a tool executor from a recipe and a list of toolboxes.
|
313
|
+
|
314
|
+
This method creates a tool executor by retrieving tools from the provided toolboxes based on the recipe.
|
315
|
+
|
316
|
+
Args:
|
317
|
+
recipe (List[str]): The recipe specifying the names of the tools to be added.
|
318
|
+
toolboxes (List[ToolBox]): The list of toolboxes to retrieve tools from.
|
319
|
+
|
320
|
+
Returns:
|
321
|
+
Self: A new instance of the tool executor with the specified tools.
|
322
|
+
"""
|
323
|
+
tools = []
|
324
|
+
while tool_name := recipe.pop(0):
|
325
|
+
for toolbox in toolboxes:
|
326
|
+
tools.append(toolbox.get(tool_name))
|
327
|
+
|
328
|
+
return cls(candidates=tools)
|