fabricatio 0.2.1.dev0__cp313-cp313-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
fabricatio/__init__.py ADDED
@@ -0,0 +1,37 @@
1
+ """Fabricatio is a Python library for building llm app using event-based agent structure."""
2
+
3
+ from fabricatio._rust_instances import template_manager
4
+ from fabricatio.core import env
5
+ from fabricatio.fs import magika
6
+ from fabricatio.journal import logger
7
+ from fabricatio.models.action import Action, WorkFlow
8
+ from fabricatio.models.events import Event
9
+ from fabricatio.models.role import Role
10
+ from fabricatio.models.task import Task
11
+ from fabricatio.models.tool import ToolBox
12
+ from fabricatio.models.utils import Message, Messages
13
+ from fabricatio.parser import Capture, CodeBlockCapture, JsonCapture, PythonCapture
14
+ from fabricatio.toolboxes import arithmetic_toolbox, basic_toolboxes, fs_toolbox, task_toolbox
15
+
16
+ __all__ = [
17
+ "Action",
18
+ "Capture",
19
+ "CodeBlockCapture",
20
+ "Event",
21
+ "JsonCapture",
22
+ "Message",
23
+ "Messages",
24
+ "PythonCapture",
25
+ "Role",
26
+ "Task",
27
+ "ToolBox",
28
+ "WorkFlow",
29
+ "arithmetic_toolbox",
30
+ "basic_toolboxes",
31
+ "env",
32
+ "fs_toolbox",
33
+ "logger",
34
+ "magika",
35
+ "task_toolbox",
36
+ "template_manager",
37
+ ]
Binary file
fabricatio/_rust.pyi ADDED
@@ -0,0 +1,53 @@
1
+ from pathlib import Path
2
+ from typing import Any, Dict, List, Optional
3
+
4
+ class TemplateManager:
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:
9
+ """Initialize the template manager.
10
+
11
+ 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.
15
+ """
16
+
17
+ @property
18
+ def template_count(self) -> int:
19
+ """Get the number of templates discovered."""
20
+
21
+ def get_template_source(self, name: str) -> Optional[str]:
22
+ """Get the source path of a template by name.
23
+
24
+ Args:
25
+ name (str): The name of the template to retrieve.
26
+
27
+ Returns:
28
+ Optional[str]: The source path of the template.
29
+ """
30
+
31
+ def discover_templates(self) -> None:
32
+ """Discover templates in the specified directories."""
33
+
34
+ def render_template(self, name: str, data: Dict[str, Any]) -> str:
35
+ """Render a template with the given name and data.
36
+
37
+ Args:
38
+ name (str): The name of the template to render.
39
+ data (Dict[str, Any]): The data to pass to the template.
40
+
41
+ Returns:
42
+ str: The rendered template.
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
+ )
@@ -0,0 +1,5 @@
1
+ """module for actions."""
2
+
3
+ from fabricatio.actions.transmission import PublishTask
4
+
5
+ __all__ = ["PublishTask"]
@@ -0,0 +1,15 @@
1
+ """Actions that involve communication with the user."""
2
+
3
+ from fabricatio.models.action import Action
4
+ from fabricatio.models.task import Task
5
+
6
+
7
+ class Examining(Action):
8
+ """Action that examines the input data."""
9
+
10
+ name: str = "talk"
11
+ output_key: str = "examine_pass"
12
+
13
+ async def _execute(self, exam_target: Task[str], to_examine: str, **_) -> bool:
14
+ """Examine the input data."""
15
+ # TODO
@@ -0,0 +1,23 @@
1
+ """Actions for transmitting tasks to targets."""
2
+
3
+ from typing import List
4
+
5
+ from fabricatio.journal import logger
6
+ from fabricatio.models.action import Action
7
+ from fabricatio.models.events import EventLike
8
+ from fabricatio.models.task import Task
9
+
10
+
11
+ class PublishTask(Action):
12
+ """An action that publishes a task to a list of targets."""
13
+
14
+ name: str = "publish_task"
15
+ """The name of the action."""
16
+ description: str = "Publish a task to a list of targets."
17
+ """The description of the action."""
18
+
19
+ async def _execute(self, send_targets: List[EventLike], send_task: Task, **_) -> None:
20
+ """Execute the action by sending the task to the specified targets."""
21
+ logger.info(f"Sending task {send_task.name} to {send_targets}")
22
+ for target in send_targets:
23
+ await send_task.move_to(target).publish()
fabricatio/config.py ADDED
@@ -0,0 +1,263 @@
1
+ """Configuration module for the Fabricatio application."""
2
+
3
+ from typing import List, Literal, Optional
4
+
5
+ from appdirs import user_config_dir
6
+ from pydantic import (
7
+ BaseModel,
8
+ ConfigDict,
9
+ DirectoryPath,
10
+ Field,
11
+ FilePath,
12
+ HttpUrl,
13
+ NonNegativeFloat,
14
+ PositiveInt,
15
+ SecretStr,
16
+ )
17
+ from pydantic_settings import (
18
+ BaseSettings,
19
+ DotEnvSettingsSource,
20
+ EnvSettingsSource,
21
+ PydanticBaseSettingsSource,
22
+ PyprojectTomlConfigSettingsSource,
23
+ SettingsConfigDict,
24
+ TomlConfigSettingsSource,
25
+ )
26
+
27
+ ROAMING_DIR = user_config_dir("fabricatio", "", roaming=True)
28
+
29
+
30
+ class LLMConfig(BaseModel):
31
+ """LLM configuration class.
32
+
33
+ Attributes:
34
+ api_endpoint (HttpUrl): OpenAI API Endpoint.
35
+ api_key (SecretStr): OpenAI API key. Empty by default for security reasons, should be set before use.
36
+ timeout (PositiveInt): The timeout of the LLM model in seconds. Default is 300 seconds as per request.
37
+ max_retries (PositiveInt): The maximum number of retries. Default is 3 retries.
38
+ model (str): The LLM model name. Set to 'gpt-3.5-turbo' as per request.
39
+ temperature (NonNegativeFloat): The temperature of the LLM model. Controls randomness in generation. Set to 1.0 as per request.
40
+ stop_sign (str): The stop sign of the LLM model. No default stop sign specified.
41
+ top_p (NonNegativeFloat): The top p of the LLM model. Controls diversity via nucleus sampling. Set to 0.35 as per request.
42
+ generation_count (PositiveInt): The number of generations to generate. Default is 1.
43
+ stream (bool): Whether to stream the LLM model's response. Default is False.
44
+ max_tokens (PositiveInt): The maximum number of tokens to generate. Set to 8192 as per request.
45
+ """
46
+
47
+ model_config = ConfigDict(use_attribute_docstrings=True)
48
+ api_endpoint: HttpUrl = Field(default=HttpUrl("https://api.openai.com"))
49
+ """OpenAI API Endpoint."""
50
+
51
+ api_key: SecretStr = Field(default=SecretStr(""))
52
+ """OpenAI API key. Empty by default for security reasons, should be set before use."""
53
+
54
+ timeout: PositiveInt = Field(default=300)
55
+ """The timeout of the LLM model in seconds. Default is 300 seconds as per request."""
56
+
57
+ max_retries: PositiveInt = Field(default=3)
58
+ """The maximum number of retries. Default is 3 retries."""
59
+
60
+ model: str = Field(default="gpt-3.5-turbo")
61
+ """The LLM model name. Set to 'gpt-3.5-turbo' as per request."""
62
+
63
+ temperature: NonNegativeFloat = Field(default=1.0)
64
+ """The temperature of the LLM model. Controls randomness in generation. Set to 1.0 as per request."""
65
+
66
+ stop_sign: str | List[str] = Field(default=("\n\n\n", "User:"))
67
+ """The stop sign of the LLM model. No default stop sign specified."""
68
+
69
+ top_p: NonNegativeFloat = Field(default=0.35)
70
+ """The top p of the LLM model. Controls diversity via nucleus sampling. Set to 0.35 as per request."""
71
+
72
+ generation_count: PositiveInt = Field(default=1)
73
+ """The number of generations to generate. Default is 1."""
74
+
75
+ stream: bool = Field(default=False)
76
+ """Whether to stream the LLM model's response. Default is False."""
77
+
78
+ max_tokens: PositiveInt = Field(default=8192)
79
+ """The maximum number of tokens to generate. Set to 8192 as per request."""
80
+
81
+
82
+ class PymitterConfig(BaseModel):
83
+ """Pymitter configuration class.
84
+
85
+ Attributes:
86
+ delimiter (str): The delimiter used to separate the event name into segments.
87
+ new_listener_event (bool): If set, a newListener event is emitted when a new listener is added.
88
+ max_listeners (int): The maximum number of listeners per event.
89
+ """
90
+
91
+ model_config = ConfigDict(use_attribute_docstrings=True)
92
+ delimiter: str = Field(default="::", frozen=True)
93
+ """The delimiter used to separate the event name into segments."""
94
+
95
+ new_listener_event: bool = Field(default=False, frozen=True)
96
+ """If set, a newListener event is emitted when a new listener is added."""
97
+
98
+ max_listeners: int = Field(default=-1, frozen=True)
99
+ """The maximum number of listeners per event."""
100
+
101
+
102
+ class DebugConfig(BaseModel):
103
+ """Debug configuration class.
104
+
105
+ Attributes:
106
+ log_level (Literal["DEBUG", "INFO", "SUCCESS", "WARNING", "ERROR", "CRITICAL"]): The log level of the application.
107
+ log_file (FilePath): The log file of the application.
108
+ """
109
+
110
+ model_config = ConfigDict(use_attribute_docstrings=True)
111
+
112
+ log_level: Literal["DEBUG", "INFO", "SUCCESS", "WARNING", "ERROR", "CRITICAL"] = Field(default="INFO")
113
+ """The log level of the application."""
114
+
115
+ log_file: FilePath = Field(default=rf"{ROAMING_DIR}\fabricatio.log")
116
+ """The log file of the application."""
117
+
118
+ rotation: int = Field(default=1)
119
+ """The rotation of the log file. in weeks."""
120
+
121
+ retention: int = Field(default=2)
122
+ """The retention of the log file. in weeks."""
123
+
124
+ streaming_visible: bool = Field(default=False)
125
+ """Whether to print the llm output when streaming."""
126
+
127
+
128
+ class TemplateConfig(BaseModel):
129
+ """Template configuration class."""
130
+
131
+ model_config = ConfigDict(use_attribute_docstrings=True)
132
+ template_dir: List[DirectoryPath] = Field(
133
+ default_factory=lambda: [DirectoryPath(r".\templates"), DirectoryPath(rf"{ROAMING_DIR}\templates")]
134
+ )
135
+ """The directory containing the templates."""
136
+ active_loading: bool = Field(default=False)
137
+ """Whether to enable active loading of templates."""
138
+
139
+ template_suffix: str = Field(default="hbs", frozen=True)
140
+ """The suffix of the templates."""
141
+
142
+ propose_task_template: str = Field(default="propose_task")
143
+ """The name of the propose task template which will be used to propose a task."""
144
+
145
+ draft_tool_usage_code_template: str = Field(default="draft_tool_usage_code")
146
+ """The name of the draft tool usage code template which will be used to draft tool usage code."""
147
+
148
+ make_choice_template: str = Field(default="make_choice")
149
+ """The name of the make choice template which will be used to make a choice."""
150
+
151
+ make_judgment_template: str = Field(default="make_judgment")
152
+ """The name of the make judgment template which will be used to make a judgment."""
153
+
154
+ dependencies_template: str = Field(default="dependencies")
155
+ """The name of the dependencies template which will be used to manage dependencies."""
156
+
157
+ task_briefing_template: str = Field(default="task_briefing")
158
+ """The name of the task briefing template which will be used to brief a task."""
159
+
160
+
161
+ class MagikaConfig(BaseModel):
162
+ """Magika configuration class."""
163
+
164
+ model_config = ConfigDict(use_attribute_docstrings=True)
165
+ model_dir: Optional[DirectoryPath] = Field(default=None)
166
+ """The directory containing the models for magika."""
167
+
168
+
169
+ class GeneralConfig(BaseModel):
170
+ """Global configuration class."""
171
+
172
+ model_config = ConfigDict(use_attribute_docstrings=True)
173
+ workspace: DirectoryPath = Field(default=DirectoryPath(r"."))
174
+ """The workspace directory for the application."""
175
+
176
+ confirm_on_ops: bool = Field(default=True)
177
+ """Whether to confirm on operations."""
178
+
179
+
180
+ class ToolBoxConfig(BaseModel):
181
+ """Toolbox configuration class."""
182
+
183
+ model_config = ConfigDict(use_attribute_docstrings=True)
184
+
185
+ tool_module_name: str = Field(default="Toolbox")
186
+ """The name of the module containing the toolbox."""
187
+
188
+ data_module_name: str = Field(default="Data")
189
+ """The name of the module containing the data."""
190
+
191
+
192
+ class Settings(BaseSettings):
193
+ """Application settings class.
194
+
195
+ Attributes:
196
+ llm (LLMConfig): LLM Configuration
197
+ debug (DebugConfig): Debug Configuration
198
+ pymitter (PymitterConfig): Pymitter Configuration
199
+ templates (TemplateConfig): Template Configuration
200
+ magika (MagikaConfig): Magika Configuration
201
+ """
202
+
203
+ model_config = SettingsConfigDict(
204
+ env_prefix="FABRIK_",
205
+ env_nested_delimiter="__",
206
+ pyproject_toml_depth=1,
207
+ pyproject_toml_table_header=("tool", "fabricatio"),
208
+ toml_file=["fabricatio.toml", rf"{ROAMING_DIR}\fabricatio.toml"],
209
+ env_file=[".env", ".envrc"],
210
+ use_attribute_docstrings=True,
211
+ )
212
+
213
+ llm: LLMConfig = Field(default_factory=LLMConfig)
214
+ """LLM Configuration"""
215
+
216
+ debug: DebugConfig = Field(default_factory=DebugConfig)
217
+ """Debug Configuration"""
218
+
219
+ pymitter: PymitterConfig = Field(default_factory=PymitterConfig)
220
+ """Pymitter Configuration"""
221
+
222
+ templates: TemplateConfig = Field(default_factory=TemplateConfig)
223
+ """Template Configuration"""
224
+
225
+ magika: MagikaConfig = Field(default_factory=MagikaConfig)
226
+ """Magika Configuration"""
227
+
228
+ general: GeneralConfig = Field(default_factory=GeneralConfig)
229
+ """General Configuration"""
230
+
231
+ toolbox: ToolBoxConfig = Field(default_factory=ToolBoxConfig)
232
+ """Toolbox Configuration"""
233
+
234
+ @classmethod
235
+ def settings_customise_sources(
236
+ cls,
237
+ settings_cls: type[BaseSettings],
238
+ init_settings: PydanticBaseSettingsSource,
239
+ env_settings: PydanticBaseSettingsSource,
240
+ dotenv_settings: PydanticBaseSettingsSource,
241
+ file_secret_settings: PydanticBaseSettingsSource,
242
+ ) -> tuple[PydanticBaseSettingsSource, ...]:
243
+ """Customize settings sources.
244
+
245
+ Args:
246
+ settings_cls (type[BaseSettings]): The settings class.
247
+ init_settings (PydanticBaseSettingsSource): Initial settings source.
248
+ env_settings (PydanticBaseSettingsSource): Environment settings source.
249
+ dotenv_settings (PydanticBaseSettingsSource): Dotenv settings source.
250
+ file_secret_settings (PydanticBaseSettingsSource): File secret settings source.
251
+
252
+ Returns:
253
+ tuple[PydanticBaseSettingsSource, ...]: A tuple of settings sources.
254
+ """
255
+ return (
256
+ DotEnvSettingsSource(settings_cls),
257
+ EnvSettingsSource(settings_cls),
258
+ TomlConfigSettingsSource(settings_cls),
259
+ PyprojectTomlConfigSettingsSource(settings_cls),
260
+ )
261
+
262
+
263
+ configs: Settings = Settings()
fabricatio/core.py ADDED
@@ -0,0 +1,167 @@
1
+ """Core module that contains the Env class for managing event handling."""
2
+
3
+ from typing import Callable, Optional, Self, overload
4
+
5
+ from pydantic import BaseModel, ConfigDict, PrivateAttr
6
+ from pymitter import EventEmitter
7
+
8
+ from fabricatio.config import configs
9
+ from fabricatio.models.events import Event
10
+
11
+
12
+ class Env(BaseModel):
13
+ """Environment class that manages event handling using EventEmitter."""
14
+
15
+ model_config = ConfigDict(use_attribute_docstrings=True)
16
+ _ee: EventEmitter = PrivateAttr(
17
+ default_factory=lambda: EventEmitter(
18
+ delimiter=configs.pymitter.delimiter,
19
+ new_listener=configs.pymitter.new_listener_event,
20
+ max_listeners=configs.pymitter.max_listeners,
21
+ wildcard=True,
22
+ )
23
+ )
24
+
25
+ @overload
26
+ def on(self, event: str | Event, /, ttl: int = -1) -> Self:
27
+ """
28
+ Registers an event listener that listens indefinitely or for a specified number of times.
29
+
30
+ Args:
31
+ event (str | Event): The event to listen for.
32
+ ttl (int): Time-to-live for the listener. If -1, the listener will listen indefinitely.
33
+
34
+ Returns:
35
+ Self: The current instance of Env.
36
+ """
37
+ ...
38
+
39
+ @overload
40
+ def on[**P, R](
41
+ self,
42
+ event: str | Event,
43
+ func: Optional[Callable[P, R]] = None,
44
+ /,
45
+ ttl: int = -1,
46
+ ) -> Callable[[Callable[P, R]], Callable[P, R]]:
47
+ """
48
+ Registers an event listener with a specific function that listens indefinitely or for a specified number of times.
49
+
50
+ Args:
51
+ event (str | Event): The event to listen for.
52
+ func (Callable[P, R]): The function to be called when the event is emitted.
53
+ ttl (int): Time-to-live for the listener. If -1, the listener will listen indefinitely.
54
+
55
+ Returns:
56
+ Callable[[Callable[P, R]], Callable[P, R]]: A decorator that registers the function as an event listener.
57
+ """
58
+ ...
59
+
60
+ def on[**P, R](
61
+ self,
62
+ event: str | Event,
63
+ func: Optional[Callable[P, R]] = None,
64
+ /,
65
+ ttl=-1,
66
+ ) -> Callable[[Callable[P, R]], Callable[P, R]] | Self:
67
+ """Registers an event listener with a specific function that listens indefinitely or for a specified number of times.
68
+
69
+ Args:
70
+ event (str | Event): The event to listen for.
71
+ func (Callable[P, R]): The function to be called when the event is emitted.
72
+ ttl (int): Time-to-live for the listener. If -1, the listener will listen indefinitely.
73
+
74
+ Returns:
75
+ Callable[[Callable[P, R]], Callable[P, R]] | Self: A decorator that registers the function as an event listener or the current instance of Env.
76
+ """
77
+ if isinstance(event, Event):
78
+ event = event.collapse()
79
+ if func is None:
80
+ return self._ee.on(event, ttl=ttl)
81
+
82
+ self._ee.on(event, func, ttl=ttl)
83
+ return self
84
+
85
+ @overload
86
+ def once[**P, R](
87
+ self,
88
+ event: str | Event,
89
+ ) -> Callable[[Callable[P, R]], Callable[P, R]]:
90
+ """
91
+ Registers an event listener that listens only once.
92
+
93
+ Args:
94
+ event (str | Event): The event to listen for.
95
+
96
+ Returns:
97
+ Callable[[Callable[P, R]], Callable[P, R]]: A decorator that registers the function as an event listener.
98
+ """
99
+ ...
100
+
101
+ @overload
102
+ def once[**P, R](
103
+ self,
104
+ event: str | Event,
105
+ func: Callable[[Callable[P, R]], Callable[P, R]],
106
+ ) -> Self:
107
+ """
108
+ Registers an event listener with a specific function that listens only once.
109
+
110
+ Args:
111
+ event (str | Event): The event to listen for.
112
+ func (Callable[P, R]): The function to be called when the event is emitted.
113
+
114
+ Returns:
115
+ Self: The current instance of Env.
116
+ """
117
+ ...
118
+
119
+ def once[**P, R](
120
+ self,
121
+ event: str | Event,
122
+ func: Optional[Callable[P, R]] = None,
123
+ ) -> Callable[[Callable[P, R]], Callable[P, R]] | Self:
124
+ """Registers an event listener with a specific function that listens only once.
125
+
126
+ Args:
127
+ event (str | Event): The event to listen for.
128
+ func (Callable[P, R]): The function to be called when the event is emitted.
129
+
130
+ Returns:
131
+ Callable[[Callable[P, R]], Callable[P, R]] | Self: A decorator that registers the function as an event listener or the current instance
132
+ """
133
+ if isinstance(event, Event):
134
+ event = event.collapse()
135
+ if func is None:
136
+ return self._ee.once(event)
137
+
138
+ self._ee.once(event, func)
139
+ return self
140
+
141
+ def emit[**P](self, event: str | Event, *args: P.args, **kwargs: P.kwargs) -> None:
142
+ """Emits an event to all registered listeners.
143
+
144
+ Args:
145
+ event (str | Event): The event to emit.
146
+ *args: Positional arguments to pass to the listeners.
147
+ **kwargs: Keyword arguments to pass to the listeners.
148
+ """
149
+ if isinstance(event, Event):
150
+ event = event.collapse()
151
+
152
+ self._ee.emit(event, *args, **kwargs)
153
+
154
+ async def emit_async[**P](self, event: str | Event, *args: P.args, **kwargs: P.kwargs) -> None:
155
+ """Asynchronously emits an event to all registered listeners.
156
+
157
+ Args:
158
+ event (str | Event): The event to emit.
159
+ *args: Positional arguments to pass to the listeners.
160
+ **kwargs: Keyword arguments to pass to the listeners.
161
+ """
162
+ if isinstance(event, Event):
163
+ event = event.collapse()
164
+ return await self._ee.emit_async(event, *args, **kwargs)
165
+
166
+
167
+ env = Env()