fabricatio 0.2.0.dev17__tar.gz → 0.2.0.dev19__tar.gz
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-0.2.0.dev17 → fabricatio-0.2.0.dev19}/Cargo.lock +54 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/Cargo.toml +3 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/PKG-INFO +1 -1
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/examples/propose_task/propose.py +1 -1
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/pyproject.toml +1 -1
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/__init__.py +5 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/_rust.pyi +21 -21
- fabricatio-0.2.0.dev19/python/fabricatio/_rust_instances.py +8 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/actions/communication.py +1 -1
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/config.py +18 -1
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/fs/curd.py +7 -1
- fabricatio-0.2.0.dev19/python/fabricatio/fs/readers.py +24 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/models/action.py +8 -9
- fabricatio-0.2.0.dev19/python/fabricatio/models/advanced.py +119 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/models/events.py +2 -2
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/models/generic.py +21 -8
- fabricatio-0.2.0.dev19/python/fabricatio/models/kwargs_types.py +26 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/models/role.py +16 -5
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/models/task.py +21 -6
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/models/tool.py +1 -1
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/models/usages.py +24 -28
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/parser.py +3 -2
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/toolboxes/__init__.py +2 -0
- fabricatio-0.2.0.dev19/src/hash.rs +17 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/src/lib.rs +2 -1
- fabricatio-0.2.0.dev19/src/templates.rs +98 -0
- fabricatio-0.2.0.dev19/templates/built-in/dependencies.hbs +16 -0
- fabricatio-0.2.0.dev19/templates/built-in/draft_tool_usage_code.hbs +52 -0
- fabricatio-0.2.0.dev19/templates.tar.gz +0 -0
- fabricatio-0.2.0.dev19/uv.lock +1855 -0
- fabricatio-0.2.0.dev17/python/fabricatio/_rust_instances.py +0 -4
- fabricatio-0.2.0.dev17/python/fabricatio/fs/readers.py +0 -7
- fabricatio-0.2.0.dev17/python/fabricatio/models/advanced.py +0 -96
- fabricatio-0.2.0.dev17/src/templates.rs +0 -112
- fabricatio-0.2.0.dev17/templates.tar.gz +0 -0
- fabricatio-0.2.0.dev17/uv.lock +0 -1857
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/.github/workflows/build-package.yaml +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/.github/workflows/ruff.yaml +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/.github/workflows/tests.yaml +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/.gitignore +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/.python-version +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/LICENSE +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/Makefile +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/README.md +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/examples/llm_usages/llm_usage.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/examples/minor/hello_fabricatio.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/examples/simple_chat/chat.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/actions/__init__.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/actions/transmission.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/core.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/decorators.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/fs/__init__.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/journal.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/models/utils.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/py.typed +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/toolboxes/arithmetic.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/toolboxes/fs.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/toolboxes/task.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/binary-exploitation-ctf-solver.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/claude-xml.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/clean-up-code.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/cryptography-ctf-solver.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/document-the-code.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/find-security-vulnerabilities.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/fix-bugs.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/improve-performance.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/make_choice.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/make_judgment.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/propose_task.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/refactor.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/reverse-engineering-ctf-solver.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/web-ctf-solver.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/write-git-commit.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/write-github-pull-request.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/templates/built-in/write-github-readme.hbs +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/tests/test_config.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/tests/test_models/test_action.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/tests/test_models/test_advanced.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/tests/test_models/test_generic.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/tests/test_models/test_role.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/tests/test_models/test_task.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/tests/test_models/test_tool.py +0 -0
- {fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/tests/test_models/test_usages.py +0 -0
@@ -67,6 +67,18 @@ dependencies = [
|
|
67
67
|
"windows-sys 0.59.0",
|
68
68
|
]
|
69
69
|
|
70
|
+
[[package]]
|
71
|
+
name = "arrayref"
|
72
|
+
version = "0.3.9"
|
73
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
74
|
+
checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
|
75
|
+
|
76
|
+
[[package]]
|
77
|
+
name = "arrayvec"
|
78
|
+
version = "0.7.6"
|
79
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
80
|
+
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
81
|
+
|
70
82
|
[[package]]
|
71
83
|
name = "atomic-waker"
|
72
84
|
version = "1.1.2"
|
@@ -106,6 +118,20 @@ version = "2.8.0"
|
|
106
118
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
107
119
|
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
108
120
|
|
121
|
+
[[package]]
|
122
|
+
name = "blake3"
|
123
|
+
version = "1.6.0"
|
124
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
125
|
+
checksum = "1230237285e3e10cde447185e8975408ae24deaa67205ce684805c25bc0c7937"
|
126
|
+
dependencies = [
|
127
|
+
"arrayref",
|
128
|
+
"arrayvec",
|
129
|
+
"cc",
|
130
|
+
"cfg-if",
|
131
|
+
"constant_time_eq",
|
132
|
+
"memmap2",
|
133
|
+
]
|
134
|
+
|
109
135
|
[[package]]
|
110
136
|
name = "block-buffer"
|
111
137
|
version = "0.10.4"
|
@@ -188,6 +214,12 @@ version = "1.0.3"
|
|
188
214
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
189
215
|
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
190
216
|
|
217
|
+
[[package]]
|
218
|
+
name = "constant_time_eq"
|
219
|
+
version = "0.3.1"
|
220
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
221
|
+
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
|
222
|
+
|
191
223
|
[[package]]
|
192
224
|
name = "core-foundation"
|
193
225
|
version = "0.9.4"
|
@@ -369,8 +401,11 @@ dependencies = [
|
|
369
401
|
name = "fabricatio"
|
370
402
|
version = "0.0.0"
|
371
403
|
dependencies = [
|
404
|
+
"blake3",
|
372
405
|
"handlebars",
|
373
406
|
"pyo3",
|
407
|
+
"pythonize",
|
408
|
+
"serde_json",
|
374
409
|
"walkdir",
|
375
410
|
]
|
376
411
|
|
@@ -910,6 +945,15 @@ version = "2.7.4"
|
|
910
945
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
911
946
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
912
947
|
|
948
|
+
[[package]]
|
949
|
+
name = "memmap2"
|
950
|
+
version = "0.9.5"
|
951
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
952
|
+
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
|
953
|
+
dependencies = [
|
954
|
+
"libc",
|
955
|
+
]
|
956
|
+
|
913
957
|
[[package]]
|
914
958
|
name = "memoffset"
|
915
959
|
version = "0.9.1"
|
@@ -1189,6 +1233,16 @@ dependencies = [
|
|
1189
1233
|
"syn",
|
1190
1234
|
]
|
1191
1235
|
|
1236
|
+
[[package]]
|
1237
|
+
name = "pythonize"
|
1238
|
+
version = "0.23.0"
|
1239
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1240
|
+
checksum = "91a6ee7a084f913f98d70cdc3ebec07e852b735ae3059a1500db2661265da9ff"
|
1241
|
+
dependencies = [
|
1242
|
+
"pyo3",
|
1243
|
+
"serde",
|
1244
|
+
]
|
1245
|
+
|
1192
1246
|
[[package]]
|
1193
1247
|
name = "quote"
|
1194
1248
|
version = "1.0.38"
|
@@ -6,8 +6,11 @@ edition = "2024"
|
|
6
6
|
crate-type = ["cdylib"]
|
7
7
|
|
8
8
|
[dependencies]
|
9
|
+
blake3 = "1.6.0"
|
9
10
|
handlebars = "6.3.1"
|
10
11
|
pyo3 = { version = "0.23.4", features = ["extension-module"] }
|
12
|
+
pythonize = "0.23.0"
|
13
|
+
serde_json = "1.0.138"
|
11
14
|
walkdir = "2.5.0"
|
12
15
|
|
13
16
|
[workspace]
|
@@ -25,7 +25,7 @@ async def main() -> None:
|
|
25
25
|
role = Role(
|
26
26
|
name="talker", description="talker role", registry={task.pending_label: WorkFlow(name="talk", steps=(Talk,))}
|
27
27
|
)
|
28
|
-
logger.info(Task.json_example())
|
28
|
+
logger.info(f"Task example:\n{Task.json_example()}")
|
29
29
|
logger.info(f"proposed task: {await role.propose('write a rust clap cli that can download a html page')}")
|
30
30
|
|
31
31
|
|
@@ -11,6 +11,7 @@ from fabricatio.models.task import Task
|
|
11
11
|
from fabricatio.models.tool import ToolBox
|
12
12
|
from fabricatio.models.utils import Message, Messages
|
13
13
|
from fabricatio.parser import Capture, CodeBlockCapture, JsonCapture, PythonCapture
|
14
|
+
from fabricatio.toolboxes import arithmetic_toolbox, basic_toolboxes, fs_toolbox, task_toolbox
|
14
15
|
|
15
16
|
__all__ = [
|
16
17
|
"Action",
|
@@ -25,8 +26,12 @@ __all__ = [
|
|
25
26
|
"Task",
|
26
27
|
"ToolBox",
|
27
28
|
"WorkFlow",
|
29
|
+
"arithmetic_toolbox",
|
30
|
+
"basic_toolboxes",
|
28
31
|
"env",
|
32
|
+
"fs_toolbox",
|
29
33
|
"logger",
|
30
34
|
"magika",
|
35
|
+
"task_toolbox",
|
31
36
|
"template_manager",
|
32
37
|
]
|
@@ -1,53 +1,53 @@
|
|
1
1
|
from pathlib import Path
|
2
|
-
from typing import
|
2
|
+
from typing import Dict, List, Optional
|
3
3
|
|
4
4
|
class TemplateManager:
|
5
|
-
|
5
|
+
"""TemplateManager class for managing handlebars templates."""
|
6
|
+
def __init__(
|
7
|
+
self, template_dirs: List[Path], suffix: Optional[str] = None, active_loading: Optional[bool] = None
|
8
|
+
) -> None:
|
6
9
|
"""Initialize the template manager.
|
7
10
|
|
8
11
|
Args:
|
9
12
|
template_dirs (List[Path]): A list of paths to directories containing templates.
|
10
|
-
suffix (str, optional): The suffix of template files. None means 'hbs' suffix
|
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.
|
11
15
|
"""
|
12
16
|
|
13
17
|
@property
|
14
18
|
def template_count(self) -> int:
|
15
19
|
"""Get the number of templates discovered."""
|
16
20
|
|
17
|
-
|
18
|
-
def templates(self) -> List[str]:
|
19
|
-
"""Get a list of template names."""
|
20
|
-
|
21
|
-
def get_template(self, name: str) -> str:
|
22
|
-
"""Get a template by name.
|
23
|
-
|
24
|
-
Args:
|
25
|
-
name (str): The name of the template to retrieve.
|
26
|
-
|
27
|
-
Returns:
|
28
|
-
str: The template content.
|
29
|
-
"""
|
30
|
-
|
31
|
-
def get_template_source(self, name: str) -> str:
|
21
|
+
def get_template_source(self, name: str) -> Optional[str]:
|
32
22
|
"""Get the source path of a template by name.
|
33
23
|
|
34
24
|
Args:
|
35
25
|
name (str): The name of the template to retrieve.
|
36
26
|
|
37
27
|
Returns:
|
38
|
-
str: The source path of the template.
|
28
|
+
Optional[str]: The source path of the template.
|
39
29
|
"""
|
40
30
|
|
41
31
|
def discover_templates(self) -> None:
|
42
32
|
"""Discover templates in the specified directories."""
|
43
33
|
|
44
|
-
def render_template(self, name: str, data: Dict[str,
|
34
|
+
def render_template(self, name: str, data: Dict[str, str]) -> str:
|
45
35
|
"""Render a template with the given name and data.
|
46
36
|
|
47
37
|
Args:
|
48
38
|
name (str): The name of the template to render.
|
49
|
-
data (Dict[str,
|
39
|
+
data (Dict[str, str]): The data to pass to the template.
|
50
40
|
|
51
41
|
Returns:
|
52
42
|
str: The rendered template.
|
53
43
|
"""
|
44
|
+
|
45
|
+
def blake3_hash(content: bytes) -> str:
|
46
|
+
"""Calculate the BLAKE3 hash of the given data.
|
47
|
+
|
48
|
+
Args:
|
49
|
+
content (bytes): The data to hash.
|
50
|
+
|
51
|
+
Returns:
|
52
|
+
str: The BLAKE3 hash of the data.
|
53
|
+
"""
|
@@ -0,0 +1,8 @@
|
|
1
|
+
from fabricatio._rust import TemplateManager
|
2
|
+
from fabricatio.config import configs
|
3
|
+
|
4
|
+
template_manager = TemplateManager(
|
5
|
+
template_dirs=configs.templates.template_dir,
|
6
|
+
suffix=configs.templates.template_suffix,
|
7
|
+
active_loading=configs.templates.active_loading,
|
8
|
+
)
|
{fabricatio-0.2.0.dev17 → fabricatio-0.2.0.dev19}/python/fabricatio/actions/communication.py
RENAMED
@@ -12,4 +12,4 @@ class Talk(Action):
|
|
12
12
|
|
13
13
|
async def _execute(self, task_input: Task[str], **_) -> str:
|
14
14
|
"""Execute the action."""
|
15
|
-
return await self.aask(task_input.briefing, system_message=task_input.
|
15
|
+
return await self.aask(task_input.briefing, system_message=task_input.dependencies_prompt())
|
@@ -63,7 +63,7 @@ class LLMConfig(BaseModel):
|
|
63
63
|
temperature: NonNegativeFloat = Field(default=1.0)
|
64
64
|
"""The temperature of the LLM model. Controls randomness in generation. Set to 1.0 as per request."""
|
65
65
|
|
66
|
-
stop_sign: str | List[str] = Field(default=("\n\n", "User:"))
|
66
|
+
stop_sign: str | List[str] = Field(default=("\n\n\n", "User:"))
|
67
67
|
"""The stop sign of the LLM model. No default stop sign specified."""
|
68
68
|
|
69
69
|
top_p: NonNegativeFloat = Field(default=0.35)
|
@@ -124,10 +124,27 @@ class TemplateConfig(BaseModel):
|
|
124
124
|
default_factory=lambda: [DirectoryPath(r".\templates"), DirectoryPath(rf"{ROAMING_DIR}\templates")]
|
125
125
|
)
|
126
126
|
"""The directory containing the templates."""
|
127
|
+
active_loading: bool = Field(default=False)
|
128
|
+
"""Whether to enable active loading of templates."""
|
127
129
|
|
128
130
|
template_suffix: str = Field(default="hbs", frozen=True)
|
129
131
|
"""The suffix of the templates."""
|
130
132
|
|
133
|
+
propose_task_template: str = Field(default="propose_task")
|
134
|
+
"""The name of the propose task template which will be used to propose a task."""
|
135
|
+
|
136
|
+
draft_tool_usage_code_template: str = Field(default="draft_tool_usage_code")
|
137
|
+
"""The name of the draft tool usage code template which will be used to draft tool usage code."""
|
138
|
+
|
139
|
+
make_choice_template: str = Field(default="make_choice")
|
140
|
+
"""The name of the make choice template which will be used to make a choice."""
|
141
|
+
|
142
|
+
make_judgment_template: str = Field(default="make_judgment")
|
143
|
+
"""The name of the make judgment template which will be used to make a judgment."""
|
144
|
+
|
145
|
+
dependencies_template: str = Field(default="dependencies")
|
146
|
+
"""The name of the dependencies template which will be used to manage dependencies."""
|
147
|
+
|
131
148
|
|
132
149
|
class MagikaConfig(BaseModel):
|
133
150
|
"""Magika configuration class."""
|
@@ -5,10 +5,11 @@ import subprocess
|
|
5
5
|
from pathlib import Path
|
6
6
|
from typing import Union
|
7
7
|
|
8
|
-
from fabricatio.decorators import depend_on_external_cmd
|
8
|
+
from fabricatio.decorators import confirm_to_execute, depend_on_external_cmd
|
9
9
|
from fabricatio.journal import logger
|
10
10
|
|
11
11
|
|
12
|
+
@confirm_to_execute
|
12
13
|
def copy_file(src: Union[str, Path], dst: Union[str, Path]) -> None:
|
13
14
|
"""Copy a file from source to destination.
|
14
15
|
|
@@ -28,6 +29,7 @@ def copy_file(src: Union[str, Path], dst: Union[str, Path]) -> None:
|
|
28
29
|
raise
|
29
30
|
|
30
31
|
|
32
|
+
@confirm_to_execute
|
31
33
|
def move_file(src: Union[str, Path], dst: Union[str, Path]) -> None:
|
32
34
|
"""Move a file from source to destination.
|
33
35
|
|
@@ -47,6 +49,7 @@ def move_file(src: Union[str, Path], dst: Union[str, Path]) -> None:
|
|
47
49
|
raise
|
48
50
|
|
49
51
|
|
52
|
+
@confirm_to_execute
|
50
53
|
def delete_file(file_path: Union[str, Path]) -> None:
|
51
54
|
"""Delete a file.
|
52
55
|
|
@@ -65,6 +68,7 @@ def delete_file(file_path: Union[str, Path]) -> None:
|
|
65
68
|
raise
|
66
69
|
|
67
70
|
|
71
|
+
@confirm_to_execute
|
68
72
|
def create_directory(dir_path: Union[str, Path], parents: bool = True, exist_ok: bool = True) -> None:
|
69
73
|
"""Create a directory.
|
70
74
|
|
@@ -81,6 +85,7 @@ def create_directory(dir_path: Union[str, Path], parents: bool = True, exist_ok:
|
|
81
85
|
raise
|
82
86
|
|
83
87
|
|
88
|
+
@confirm_to_execute
|
84
89
|
@depend_on_external_cmd(
|
85
90
|
"erd",
|
86
91
|
"Please install `erd` using `cargo install erdtree` or `scoop install erdtree`.",
|
@@ -92,6 +97,7 @@ def tree(dir_path: Union[str, Path]) -> str:
|
|
92
97
|
return subprocess.check_output(("erd", dir_path.as_posix()), encoding="utf-8") # noqa: S603
|
93
98
|
|
94
99
|
|
100
|
+
@confirm_to_execute
|
95
101
|
def delete_directory(dir_path: Union[str, Path]) -> None:
|
96
102
|
"""Delete a directory and its contents.
|
97
103
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
"""Filesystem readers for Fabricatio."""
|
2
|
+
|
3
|
+
from pathlib import Path
|
4
|
+
|
5
|
+
from magika import Magika
|
6
|
+
|
7
|
+
from fabricatio.config import configs
|
8
|
+
|
9
|
+
magika = Magika(model_dir=configs.magika.model_dir)
|
10
|
+
|
11
|
+
|
12
|
+
def safe_text_read(path: Path) -> str:
|
13
|
+
"""Safely read the text from a file.
|
14
|
+
|
15
|
+
Args:
|
16
|
+
path (Path): The path to the file.
|
17
|
+
|
18
|
+
Returns:
|
19
|
+
str: The text from the file.
|
20
|
+
"""
|
21
|
+
try:
|
22
|
+
return path.read_text(encoding="utf-8")
|
23
|
+
except (UnicodeDecodeError, IsADirectoryError, FileNotFoundError):
|
24
|
+
return ""
|
@@ -3,17 +3,17 @@
|
|
3
3
|
import traceback
|
4
4
|
from abc import abstractmethod
|
5
5
|
from asyncio import Queue
|
6
|
-
from typing import Any, Dict, Self, Tuple, Type, Unpack
|
6
|
+
from typing import Any, Dict, Self, Tuple, Type, Union, Unpack
|
7
7
|
|
8
8
|
from fabricatio.journal import logger
|
9
|
-
from fabricatio.models.advanced import ProposeTask
|
9
|
+
from fabricatio.models.advanced import HandleTask, ProposeTask
|
10
10
|
from fabricatio.models.generic import WithBriefing
|
11
11
|
from fabricatio.models.task import Task
|
12
12
|
from fabricatio.models.usages import ToolBoxUsage
|
13
13
|
from pydantic import Field, PrivateAttr
|
14
14
|
|
15
15
|
|
16
|
-
class Action(
|
16
|
+
class Action(HandleTask, ProposeTask):
|
17
17
|
"""Class that represents an action to be executed in a workflow."""
|
18
18
|
|
19
19
|
personality: str = Field(default="")
|
@@ -52,7 +52,7 @@ class Action(ProposeTask, ToolBoxUsage):
|
|
52
52
|
return f"# The action you are going to perform: \n{super().briefing}"
|
53
53
|
|
54
54
|
|
55
|
-
class WorkFlow[A: Type[Action]
|
55
|
+
class WorkFlow[A: Union[Type[Action], Action]](WithBriefing, ToolBoxUsage):
|
56
56
|
"""Class that represents a workflow to be executed in a task."""
|
57
57
|
|
58
58
|
_context: Queue[Dict[str, Any]] = PrivateAttr(default_factory=lambda: Queue(maxsize=1))
|
@@ -102,13 +102,12 @@ class WorkFlow[A: Type[Action] | Action](WithBriefing, ToolBoxUsage):
|
|
102
102
|
task: The task to be served.
|
103
103
|
"""
|
104
104
|
await task.start()
|
105
|
-
await self._init_context()
|
105
|
+
await self._init_context(task)
|
106
106
|
current_action = None
|
107
107
|
try:
|
108
108
|
for step in self._instances:
|
109
109
|
logger.debug(f"Executing step: {step.name}")
|
110
|
-
|
111
|
-
modified_ctx = await step.act(cxt)
|
110
|
+
modified_ctx = await step.act(await self._context.get())
|
112
111
|
await self._context.put(modified_ctx)
|
113
112
|
current_action = step.name
|
114
113
|
logger.info(f"Finished executing workflow: {self.name}")
|
@@ -118,10 +117,10 @@ class WorkFlow[A: Type[Action] | Action](WithBriefing, ToolBoxUsage):
|
|
118
117
|
logger.error(traceback.format_exc()) # Add this line to log the traceback
|
119
118
|
await task.fail() # Mark the task as failed
|
120
119
|
|
121
|
-
async def _init_context(self) -> None:
|
120
|
+
async def _init_context[T](self, task: Task[T]) -> None:
|
122
121
|
"""Initialize the context dictionary for workflow execution."""
|
123
122
|
logger.debug(f"Initializing context for workflow: {self.name}")
|
124
|
-
await self._context.put({self.task_input_key:
|
123
|
+
await self._context.put({self.task_input_key: task, **dict(self.extra_init_context)})
|
125
124
|
|
126
125
|
def steps_fallback_to_self(self) -> Self:
|
127
126
|
"""Set the fallback for each step to the workflow itself."""
|
@@ -0,0 +1,119 @@
|
|
1
|
+
"""A module for advanced models and functionalities."""
|
2
|
+
|
3
|
+
from types import CodeType
|
4
|
+
from typing import List, Optional, Tuple, Unpack
|
5
|
+
|
6
|
+
import orjson
|
7
|
+
from fabricatio._rust_instances import template_manager
|
8
|
+
from fabricatio.config import configs
|
9
|
+
from fabricatio.models.generic import WithBriefing
|
10
|
+
from fabricatio.models.kwargs_types import LLMKwargs
|
11
|
+
from fabricatio.models.task import Task
|
12
|
+
from fabricatio.models.tool import Tool, ToolExecutor
|
13
|
+
from fabricatio.models.usages import LLMUsage, ToolBoxUsage
|
14
|
+
from fabricatio.parser import JsonCapture, PythonCapture
|
15
|
+
from loguru import logger
|
16
|
+
from pydantic import PositiveInt, ValidationError
|
17
|
+
|
18
|
+
|
19
|
+
class ProposeTask(WithBriefing, LLMUsage):
|
20
|
+
"""A class that proposes a task based on a prompt."""
|
21
|
+
|
22
|
+
async def propose[T](
|
23
|
+
self,
|
24
|
+
prompt: str,
|
25
|
+
max_validations: PositiveInt = 2,
|
26
|
+
**kwargs: Unpack[LLMKwargs],
|
27
|
+
) -> Task[T]:
|
28
|
+
"""Asynchronously proposes a task based on a given prompt and parameters.
|
29
|
+
|
30
|
+
Parameters:
|
31
|
+
prompt: The prompt text for proposing a task, which is a string that must be provided.
|
32
|
+
max_validations: The maximum number of validations allowed, default is 2.
|
33
|
+
**kwargs: The keyword arguments for the LLM (Large Language Model) usage.
|
34
|
+
|
35
|
+
Returns:
|
36
|
+
A Task object based on the proposal result.
|
37
|
+
"""
|
38
|
+
if not prompt:
|
39
|
+
err = f"{self.name}: Prompt must be provided."
|
40
|
+
logger.error(err)
|
41
|
+
raise ValueError(err)
|
42
|
+
|
43
|
+
def _validate_json(response: str) -> None | Task:
|
44
|
+
try:
|
45
|
+
cap = JsonCapture.capture(response)
|
46
|
+
logger.debug(f"Response: \n{response}")
|
47
|
+
logger.info(f"Captured JSON: \n{cap}")
|
48
|
+
return Task.model_validate_json(cap)
|
49
|
+
except ValidationError as e:
|
50
|
+
logger.error(f"Failed to parse task from JSON: {e}")
|
51
|
+
return None
|
52
|
+
|
53
|
+
template_data = {"prompt": prompt, "json_example": Task.json_example()}
|
54
|
+
return await self.aask_validate(
|
55
|
+
question=template_manager.render_template(configs.templates.propose_task_template, template_data),
|
56
|
+
validator=_validate_json,
|
57
|
+
system_message=f"# your personal briefing: \n{self.briefing}",
|
58
|
+
max_validations=max_validations,
|
59
|
+
**kwargs,
|
60
|
+
)
|
61
|
+
|
62
|
+
|
63
|
+
class HandleTask(WithBriefing, ToolBoxUsage):
|
64
|
+
"""A class that handles a task based on a task object."""
|
65
|
+
|
66
|
+
async def draft_tool_usage_code(
|
67
|
+
self,
|
68
|
+
task: Task,
|
69
|
+
tools: List[Tool],
|
70
|
+
**kwargs: Unpack[LLMKwargs],
|
71
|
+
) -> Tuple[CodeType, List[str]]:
|
72
|
+
"""Asynchronously drafts the tool usage code for a task based on a given task object and tools."""
|
73
|
+
logger.info(f"Drafting tool usage code for task: {task.briefing}")
|
74
|
+
|
75
|
+
if not tools:
|
76
|
+
err = f"{self.name}: Tools must be provided to draft the tool usage code."
|
77
|
+
logger.error(err)
|
78
|
+
raise ValueError(err)
|
79
|
+
|
80
|
+
def _validator(response: str) -> Tuple[CodeType, List[str]] | None:
|
81
|
+
if (source := PythonCapture.convert_with(response, lambda resp: compile(resp, "<string>", "exec"))) and (
|
82
|
+
to_extract := JsonCapture.convert_with(response, orjson.loads)
|
83
|
+
):
|
84
|
+
return source, to_extract
|
85
|
+
return None
|
86
|
+
|
87
|
+
return await self.aask_validate(
|
88
|
+
question=template_manager.render_template(
|
89
|
+
configs.templates.draft_tool_usage_code_template,
|
90
|
+
{
|
91
|
+
"tool_module_name": configs.toolbox.tool_module_name,
|
92
|
+
"task": task.briefing,
|
93
|
+
"tools": [tool.briefing for tool in tools],
|
94
|
+
},
|
95
|
+
),
|
96
|
+
validator=_validator,
|
97
|
+
system_message=f"# your personal briefing: \n{self.briefing}",
|
98
|
+
**kwargs,
|
99
|
+
)
|
100
|
+
|
101
|
+
async def handle_fin_grind(
|
102
|
+
self,
|
103
|
+
task: Task,
|
104
|
+
**kwargs: Unpack[LLMKwargs],
|
105
|
+
) -> Optional[Tuple]:
|
106
|
+
"""Asynchronously handles a task based on a given task object and parameters."""
|
107
|
+
logger.info(f"Handling task: {task.briefing}")
|
108
|
+
|
109
|
+
tools = await self.gather_tools(task)
|
110
|
+
logger.info(f"{self.name} have gathered {len(tools)} tools gathered")
|
111
|
+
|
112
|
+
if tools:
|
113
|
+
executor = ToolExecutor(execute_sequence=tools)
|
114
|
+
code, to_extract = await self.draft_tool_usage_code(task, tools, **kwargs)
|
115
|
+
cxt = await executor.execute(code)
|
116
|
+
if to_extract:
|
117
|
+
return tuple(cxt.get(k) for k in to_extract)
|
118
|
+
|
119
|
+
return None
|
@@ -1,11 +1,11 @@
|
|
1
1
|
"""The module containing the Event class."""
|
2
2
|
|
3
|
-
from typing import List, Self
|
3
|
+
from typing import List, Self, Union
|
4
4
|
|
5
5
|
from fabricatio.config import configs
|
6
6
|
from pydantic import BaseModel, ConfigDict, Field
|
7
7
|
|
8
|
-
type EventLike = str
|
8
|
+
type EventLike = Union[str, List[str], "Event"]
|
9
9
|
|
10
10
|
|
11
11
|
class Event(BaseModel):
|
@@ -4,7 +4,10 @@ from pathlib import Path
|
|
4
4
|
from typing import List, Self
|
5
5
|
|
6
6
|
import orjson
|
7
|
-
from fabricatio.
|
7
|
+
from fabricatio._rust import blake3_hash
|
8
|
+
from fabricatio._rust_instances import template_manager
|
9
|
+
from fabricatio.config import configs
|
10
|
+
from fabricatio.fs.readers import magika, safe_text_read
|
8
11
|
from pydantic import (
|
9
12
|
BaseModel,
|
10
13
|
ConfigDict,
|
@@ -96,15 +99,25 @@ class WithDependency(Base):
|
|
96
99
|
self.dependencies.remove(Path(d).as_posix())
|
97
100
|
return self
|
98
101
|
|
99
|
-
|
102
|
+
@property
|
103
|
+
def dependencies_prompt(self) -> str:
|
100
104
|
"""Generate a prompt for the task based on the file dependencies.
|
101
105
|
|
102
106
|
Returns:
|
103
107
|
str: The generated prompt for the task.
|
104
108
|
"""
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
109
|
+
return template_manager.render_template(
|
110
|
+
configs.templates.dependencies_template,
|
111
|
+
{
|
112
|
+
(pth := Path(p)).as_posix(): {
|
113
|
+
"exists": pth.exists(),
|
114
|
+
"description": (identity := magika.identify_path(pth)).output.description,
|
115
|
+
"size": f"{pth.stat().st_size / (1024 * 1024) if pth.exists() and pth.is_file() else 0:.3f} MB",
|
116
|
+
"content": (text := safe_text_read(pth)),
|
117
|
+
"lines": len(text.splitlines()),
|
118
|
+
"language": identity.output.ct_label,
|
119
|
+
"checksum": blake3_hash(pth.read_bytes()) if pth.exists() and pth.is_file() else "unknown",
|
120
|
+
}
|
121
|
+
for p in self.dependencies
|
122
|
+
},
|
123
|
+
)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
"""This module contains the types for the keyword arguments of the methods in the models module."""
|
2
|
+
|
3
|
+
from typing import List, NotRequired, TypedDict
|
4
|
+
|
5
|
+
from pydantic import NonNegativeFloat, NonNegativeInt, PositiveInt
|
6
|
+
|
7
|
+
|
8
|
+
class LLMKwargs(TypedDict):
|
9
|
+
"""A type representing the keyword arguments for the LLM (Large Language Model) usage."""
|
10
|
+
|
11
|
+
model: NotRequired[str]
|
12
|
+
temperature: NotRequired[NonNegativeFloat]
|
13
|
+
stop: NotRequired[str | List[str]]
|
14
|
+
top_p: NotRequired[NonNegativeFloat]
|
15
|
+
max_tokens: NotRequired[PositiveInt]
|
16
|
+
stream: NotRequired[bool]
|
17
|
+
timeout: NotRequired[PositiveInt]
|
18
|
+
max_retries: NotRequired[PositiveInt]
|
19
|
+
|
20
|
+
|
21
|
+
class ChooseKwargs(LLMKwargs):
|
22
|
+
"""A type representing the keyword arguments for the choose method."""
|
23
|
+
|
24
|
+
max_validations: NotRequired[PositiveInt]
|
25
|
+
system_message: NotRequired[str]
|
26
|
+
k: NotRequired[NonNegativeInt]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"""Module that contains the Role class."""
|
2
2
|
|
3
|
-
from typing import Any, Set
|
3
|
+
from typing import Any, Self, Set
|
4
4
|
|
5
5
|
from fabricatio.core import env
|
6
6
|
from fabricatio.journal import logger
|
@@ -22,8 +22,22 @@ class Role(ProposeTask, ToolBoxUsage):
|
|
22
22
|
toolboxes: Set[ToolBox] = Field(default=basic_toolboxes)
|
23
23
|
|
24
24
|
def model_post_init(self, __context: Any) -> None:
|
25
|
+
"""Register the workflows in the role to the event bus."""
|
26
|
+
self.resolve_configuration().register_workflows()
|
27
|
+
|
28
|
+
def register_workflows(self) -> Self:
|
25
29
|
"""Register the workflows in the role to the event bus."""
|
26
30
|
for event, workflow in self.registry.items():
|
31
|
+
logger.debug(
|
32
|
+
f"Registering workflow: `{workflow.name}` for event: `{Event.instantiate_from(event).collapse()}`"
|
33
|
+
)
|
34
|
+
env.on(event, workflow.serve)
|
35
|
+
return self
|
36
|
+
|
37
|
+
def resolve_configuration(self) -> Self:
|
38
|
+
"""Resolve the configuration of the role."""
|
39
|
+
for workflow in self.registry.values():
|
40
|
+
logger.debug(f"Resolving config for workflow: `{workflow.name}`")
|
27
41
|
(
|
28
42
|
workflow.fallback_to(self)
|
29
43
|
.steps_fallback_to_self()
|
@@ -32,7 +46,4 @@ class Role(ProposeTask, ToolBoxUsage):
|
|
32
46
|
.steps_supply_tools_from_self()
|
33
47
|
)
|
34
48
|
|
35
|
-
|
36
|
-
f"Registering workflow: {workflow.name} for event: {event.collapse() if isinstance(event, Event) else event}"
|
37
|
-
)
|
38
|
-
env.on(event, workflow.serve)
|
49
|
+
return self
|