fabricatio 0.2.6__cp39-cp39-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.
Files changed (42) hide show
  1. fabricatio/__init__.py +43 -0
  2. fabricatio/_rust.cp39-win_amd64.pyd +0 -0
  3. fabricatio/_rust.pyi +115 -0
  4. fabricatio/_rust_instances.py +10 -0
  5. fabricatio/actions/article.py +128 -0
  6. fabricatio/actions/output.py +19 -0
  7. fabricatio/actions/rag.py +71 -0
  8. fabricatio/capabilities/correct.py +115 -0
  9. fabricatio/capabilities/propose.py +49 -0
  10. fabricatio/capabilities/rag.py +384 -0
  11. fabricatio/capabilities/rating.py +339 -0
  12. fabricatio/capabilities/review.py +278 -0
  13. fabricatio/capabilities/task.py +113 -0
  14. fabricatio/config.py +405 -0
  15. fabricatio/core.py +181 -0
  16. fabricatio/decorators.py +179 -0
  17. fabricatio/fs/__init__.py +29 -0
  18. fabricatio/fs/curd.py +149 -0
  19. fabricatio/fs/readers.py +46 -0
  20. fabricatio/journal.py +21 -0
  21. fabricatio/models/action.py +230 -0
  22. fabricatio/models/events.py +120 -0
  23. fabricatio/models/extra.py +655 -0
  24. fabricatio/models/generic.py +406 -0
  25. fabricatio/models/kwargs_types.py +169 -0
  26. fabricatio/models/role.py +72 -0
  27. fabricatio/models/task.py +299 -0
  28. fabricatio/models/tool.py +189 -0
  29. fabricatio/models/usages.py +718 -0
  30. fabricatio/models/utils.py +192 -0
  31. fabricatio/parser.py +151 -0
  32. fabricatio/py.typed +0 -0
  33. fabricatio/toolboxes/__init__.py +15 -0
  34. fabricatio/toolboxes/arithmetic.py +62 -0
  35. fabricatio/toolboxes/fs.py +31 -0
  36. fabricatio/workflows/articles.py +26 -0
  37. fabricatio/workflows/rag.py +11 -0
  38. fabricatio-0.2.6.data/scripts/tdown.exe +0 -0
  39. fabricatio-0.2.6.dist-info/METADATA +432 -0
  40. fabricatio-0.2.6.dist-info/RECORD +42 -0
  41. fabricatio-0.2.6.dist-info/WHEEL +4 -0
  42. fabricatio-0.2.6.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,406 @@
1
+ """This module defines generic classes for models in the Fabricatio library."""
2
+
3
+ from abc import abstractmethod
4
+ from pathlib import Path
5
+ from typing import Any, Callable, Dict, Iterable, List, Optional, Self, Union, final, overload
6
+
7
+ import orjson
8
+ from fabricatio._rust import blake3_hash
9
+ from fabricatio._rust_instances import TEMPLATE_MANAGER
10
+ from fabricatio.config import configs
11
+ from fabricatio.fs.readers import MAGIKA, safe_text_read
12
+ from fabricatio.journal import logger
13
+ from fabricatio.parser import JsonCapture
14
+ from pydantic import (
15
+ BaseModel,
16
+ ConfigDict,
17
+ Field,
18
+ HttpUrl,
19
+ NonNegativeFloat,
20
+ PositiveFloat,
21
+ PositiveInt,
22
+ SecretStr,
23
+ )
24
+
25
+
26
+ class Base(BaseModel):
27
+ """Base class for all models with Pydantic configuration."""
28
+
29
+ model_config = ConfigDict(use_attribute_docstrings=True)
30
+
31
+
32
+ class Display(Base):
33
+ """Class that provides a method to display the model in a formatted JSON string."""
34
+
35
+ def display(self) -> str:
36
+ """Display the model in a formatted JSON string.
37
+
38
+ Returns:
39
+ str: The formatted JSON string of the model.
40
+ """
41
+ return self.model_dump_json(indent=1)
42
+
43
+ def compact(self) -> str:
44
+ """Display the model in a compact JSON string.
45
+
46
+ Returns:
47
+ str: The compact JSON string of the model.
48
+ """
49
+ return self.model_dump_json()
50
+
51
+
52
+ class Named(Base):
53
+ """Class that includes a name attribute."""
54
+
55
+ name: str = Field(frozen=True)
56
+ """The name of the object."""
57
+
58
+
59
+ class Described(Base):
60
+ """Class that includes a description attribute."""
61
+
62
+ description: str = Field(default="", frozen=True)
63
+ """The description of the object."""
64
+
65
+
66
+ class WithBriefing(Named, Described):
67
+ """Class that provides a briefing based on the name and description."""
68
+
69
+ @property
70
+ def briefing(self) -> str:
71
+ """Get the briefing of the object.
72
+
73
+ Returns:
74
+ str: The briefing of the object.
75
+ """
76
+ return f"{self.name}: {self.description}" if self.description else self.name
77
+
78
+ def prepend[D: Dict[str, Any]](self, kwargs: D) -> D:
79
+ """Prepend the briefing to the system message in the kwargs.
80
+
81
+ Args:
82
+ kwargs (Dict[str, Any]): The keyword arguments to modify.
83
+
84
+ Returns:
85
+ Dict[str, Any]: The modified keyword arguments.
86
+ """
87
+ kwargs["system_message"] = f"# your personal briefing: \n{self.briefing}\n" + kwargs.get("system_message", "")
88
+ return kwargs
89
+
90
+
91
+ class WithFormatedJsonSchema(Base):
92
+ """Class that provides a formatted JSON schema of the model."""
93
+
94
+ @classmethod
95
+ def formated_json_schema(cls) -> str:
96
+ """Get the JSON schema of the model in a formatted string.
97
+
98
+ Returns:
99
+ str: The JSON schema of the model in a formatted string.
100
+ """
101
+ return orjson.dumps(
102
+ cls.model_json_schema(),
103
+ option=orjson.OPT_INDENT_2 | orjson.OPT_SORT_KEYS,
104
+ ).decode()
105
+
106
+
107
+ class CreateJsonObjPrompt(WithFormatedJsonSchema):
108
+ """Class that provides a prompt for creating a JSON object."""
109
+
110
+ @classmethod
111
+ @overload
112
+ def create_json_prompt(cls, requirement: List[str]) -> List[str]: ...
113
+
114
+ @classmethod
115
+ @overload
116
+ def create_json_prompt(cls, requirement: str) -> str: ...
117
+
118
+ @classmethod
119
+ def create_json_prompt(cls, requirement: str | List[str]) -> str | List[str]:
120
+ """Create the prompt for creating a JSON object with given requirement.
121
+
122
+ Args:
123
+ requirement (str): The requirement for the JSON object.
124
+
125
+ Returns:
126
+ str: The prompt for creating a JSON object with given requirement.
127
+ """
128
+ if isinstance(requirement, str):
129
+ return TEMPLATE_MANAGER.render_template(
130
+ configs.templates.create_json_obj_template,
131
+ {"requirement": requirement, "json_schema": cls.formated_json_schema()},
132
+ )
133
+ return [
134
+ TEMPLATE_MANAGER.render_template(
135
+ configs.templates.create_json_obj_template,
136
+ {"requirement": r, "json_schema": cls.formated_json_schema()},
137
+ )
138
+ for r in requirement
139
+ ]
140
+
141
+
142
+ class InstantiateFromString(Base):
143
+ """Class that provides a method to instantiate the class from a string."""
144
+
145
+ @classmethod
146
+ def instantiate_from_string(cls, string: str) -> Self | None:
147
+ """Instantiate the class from a string.
148
+
149
+ Args:
150
+ string (str): The string to instantiate the class from.
151
+
152
+ Returns:
153
+ Self | None: The instance of the class or None if the string is not valid.
154
+ """
155
+ return JsonCapture.convert_with(string, cls.model_validate_json)
156
+
157
+
158
+ class ProposedAble(CreateJsonObjPrompt, InstantiateFromString):
159
+ """Class that provides a method to propose a JSON object based on the requirement."""
160
+
161
+ pass
162
+
163
+
164
+ class FinalizedDumpAble(Base):
165
+ """Class that provides a method to finalize the dump of the object."""
166
+
167
+ @abstractmethod
168
+ def finalized_dump(self) -> str:
169
+ """Finalize the dump of the object.
170
+
171
+ Returns:
172
+ str: The finalized dump of the object.
173
+ """
174
+
175
+ def finalized_dump_to(self, path: str | Path) -> Self:
176
+ """Finalize the dump of the object to a file.
177
+
178
+ Args:
179
+ path (str | Path): The path to save the finalized dump.
180
+
181
+ Returns:
182
+ Self: The current instance of the object.
183
+ """
184
+ Path(path).write_text(self.finalized_dump(), encoding="utf-8")
185
+ return self
186
+
187
+
188
+ class WithDependency(Base):
189
+ """Class that manages file dependencies."""
190
+
191
+ dependencies: List[str] = Field(default_factory=list)
192
+ """The file dependencies which is needed to read or write to meet a specific requirement, a list of file paths."""
193
+
194
+ def add_dependency[P: str | Path](self, dependency: P | List[P]) -> Self:
195
+ """Add a file dependency to the task.
196
+
197
+ Args:
198
+ dependency (str | Path | List[str | Path]): The file dependency to add to the task.
199
+
200
+ Returns:
201
+ Self: The current instance of the task.
202
+ """
203
+ if not isinstance(dependency, list):
204
+ dependency = [dependency]
205
+ self.dependencies.extend(Path(d).as_posix() for d in dependency)
206
+ return self
207
+
208
+ def remove_dependency[P: str | Path](self, dependency: P | List[P]) -> Self:
209
+ """Remove a file dependency from the task.
210
+
211
+ Args:
212
+ dependency (str | Path | List[str | Path]): The file dependency to remove from the task.
213
+
214
+ Returns:
215
+ Self: The current instance of the task.
216
+ """
217
+ if not isinstance(dependency, list):
218
+ dependency = [dependency]
219
+ for d in dependency:
220
+ self.dependencies.remove(Path(d).as_posix())
221
+ return self
222
+
223
+ def clear_dependencies(self) -> Self:
224
+ """Clear all file dependencies from the task.
225
+
226
+ Returns:
227
+ Self: The current instance of the task.
228
+ """
229
+ self.dependencies.clear()
230
+ return self
231
+
232
+ def override_dependencies[P: str | Path](self, dependencies: List[P] | P) -> Self:
233
+ """Override the file dependencies of the task.
234
+
235
+ Args:
236
+ dependencies (List[str | Path] | str | Path): The file dependencies to override the task's dependencies.
237
+
238
+ Returns:
239
+ Self: The current instance of the task.
240
+ """
241
+ return self.clear_dependencies().add_dependency(dependencies)
242
+
243
+ def pop_dependence[T](self, idx: int = -1, reader: Callable[[str], T] = safe_text_read) -> T:
244
+ """Pop the file dependencies from the task.
245
+
246
+ Returns:
247
+ str: The popped file dependency
248
+ """
249
+ return reader(self.dependencies.pop(idx))
250
+
251
+ @property
252
+ def dependencies_prompt(self) -> str:
253
+ """Generate a prompt for the task based on the file dependencies.
254
+
255
+ Returns:
256
+ str: The generated prompt for the task.
257
+ """
258
+ return TEMPLATE_MANAGER.render_template(
259
+ configs.templates.dependencies_template,
260
+ {
261
+ (pth := Path(p)).name: {
262
+ "path": pth.as_posix(),
263
+ "exists": pth.exists(),
264
+ "description": (identity := MAGIKA.identify_path(pth)).output.description,
265
+ "size": f"{pth.stat().st_size / (1024 * 1024) if pth.exists() and pth.is_file() else 0:.3f} MB",
266
+ "content": (text := safe_text_read(pth)),
267
+ "lines": len(text.splitlines()),
268
+ "language": identity.output.ct_label,
269
+ "checksum": blake3_hash(pth.read_bytes()) if pth.exists() and pth.is_file() else "unknown",
270
+ }
271
+ for p in self.dependencies
272
+ },
273
+ )
274
+
275
+
276
+ class PrepareVectorization(Base):
277
+ """Class that prepares the vectorization of the model."""
278
+
279
+ @abstractmethod
280
+ def _prepare_vectorization_inner(self) -> str:
281
+ """Prepare the vectorization of the model."""
282
+
283
+ def prepare_vectorization(self, max_length: Optional[int] = None) -> str:
284
+ """Prepare the vectorization of the model.
285
+
286
+ Returns:
287
+ str: The prepared vectorization of the model.
288
+ """
289
+ max_length = max_length or configs.embedding.max_sequence_length
290
+ chunk = self._prepare_vectorization_inner()
291
+ if len(chunk) > max_length:
292
+ logger.error(err := f"Chunk exceeds maximum sequence length {max_length}.")
293
+ raise ValueError(err)
294
+
295
+ return chunk
296
+
297
+
298
+ class ScopedConfig(Base):
299
+ """Class that manages a scoped configuration."""
300
+
301
+ llm_api_endpoint: Optional[HttpUrl] = None
302
+ """The OpenAI API endpoint."""
303
+
304
+ llm_api_key: Optional[SecretStr] = None
305
+ """The OpenAI API key."""
306
+
307
+ llm_timeout: Optional[PositiveInt] = None
308
+ """The timeout of the LLM model."""
309
+
310
+ llm_max_retries: Optional[PositiveInt] = None
311
+ """The maximum number of retries."""
312
+
313
+ llm_model: Optional[str] = None
314
+ """The LLM model name."""
315
+
316
+ llm_temperature: Optional[NonNegativeFloat] = None
317
+ """The temperature of the LLM model."""
318
+
319
+ llm_stop_sign: Optional[str | List[str]] = None
320
+ """The stop sign of the LLM model."""
321
+
322
+ llm_top_p: Optional[NonNegativeFloat] = None
323
+ """The top p of the LLM model."""
324
+
325
+ llm_generation_count: Optional[PositiveInt] = None
326
+ """The number of generations to generate."""
327
+
328
+ llm_stream: Optional[bool] = None
329
+ """Whether to stream the LLM model's response."""
330
+
331
+ llm_max_tokens: Optional[PositiveInt] = None
332
+ """The maximum number of tokens to generate."""
333
+
334
+ llm_tpm: Optional[PositiveInt] = None
335
+ """The tokens per minute of the LLM model."""
336
+
337
+ llm_rpm: Optional[PositiveInt] = None
338
+ """The requests per minute of the LLM model."""
339
+
340
+ embedding_api_endpoint: Optional[HttpUrl] = None
341
+ """The OpenAI API endpoint."""
342
+
343
+ embedding_api_key: Optional[SecretStr] = None
344
+ """The OpenAI API key."""
345
+
346
+ embedding_timeout: Optional[PositiveInt] = None
347
+ """The timeout of the LLM model."""
348
+
349
+ embedding_model: Optional[str] = None
350
+ """The LLM model name."""
351
+
352
+ embedding_max_sequence_length: Optional[PositiveInt] = None
353
+ """The maximum sequence length."""
354
+
355
+ embedding_dimensions: Optional[PositiveInt] = None
356
+ """The dimensions of the embedding."""
357
+ embedding_caching: Optional[bool] = False
358
+ """Whether to cache the embedding result."""
359
+
360
+ milvus_uri: Optional[HttpUrl] = Field(default=None)
361
+ """The URI of the Milvus server."""
362
+ milvus_token: Optional[SecretStr] = Field(default=None)
363
+ """The token for the Milvus server."""
364
+ milvus_timeout: Optional[PositiveFloat] = Field(default=None)
365
+ """The timeout for the Milvus server."""
366
+ milvus_dimensions: Optional[PositiveInt] = Field(default=None)
367
+ """The dimensions of the Milvus server."""
368
+
369
+ @final
370
+ def fallback_to(self, other: "ScopedConfig") -> Self:
371
+ """Fallback to another instance's attribute values if the current instance's attributes are None.
372
+
373
+ Args:
374
+ other (LLMUsage): Another instance from which to copy attribute values.
375
+
376
+ Returns:
377
+ Self: The current instance, allowing for method chaining.
378
+ """
379
+ # Iterate over the attribute names and copy values from 'other' to 'self' where applicable
380
+ # noinspection PydanticTypeChecker,PyTypeChecker
381
+ for attr_name in ScopedConfig.model_fields:
382
+ # Copy the attribute value from 'other' to 'self' only if 'self' has None and 'other' has a non-None value
383
+ if getattr(self, attr_name) is None and (attr := getattr(other, attr_name)) is not None:
384
+ setattr(self, attr_name, attr)
385
+
386
+ # Return the current instance to allow for method chaining
387
+ return self
388
+
389
+ @final
390
+ def hold_to(self, others: Union["ScopedConfig", Iterable["ScopedConfig"]]) -> Self:
391
+ """Hold to another instance's attribute values if the current instance's attributes are None.
392
+
393
+ Args:
394
+ others (LLMUsage | Iterable[LLMUsage]): Another instance or iterable of instances from which to copy attribute values.
395
+
396
+ Returns:
397
+ Self: The current instance, allowing for method chaining.
398
+ """
399
+ if not isinstance(others, Iterable):
400
+ others = [others]
401
+ for other in others:
402
+ # noinspection PyTypeChecker,PydanticTypeChecker
403
+ for attr_name in ScopedConfig.model_fields:
404
+ if (attr := getattr(self, attr_name)) is not None and getattr(other, attr_name) is None:
405
+ setattr(other, attr_name, attr)
406
+ return self
@@ -0,0 +1,169 @@
1
+ """This module contains the types for the keyword arguments of the methods in the models module."""
2
+
3
+ from importlib.util import find_spec
4
+ from typing import Any, Required, TypedDict
5
+
6
+ from litellm.caching.caching import CacheMode
7
+ from litellm.types.caching import CachingSupportedCallTypes
8
+
9
+ if find_spec("pymilvus"):
10
+ from pymilvus import CollectionSchema
11
+ from pymilvus.milvus_client import IndexParams
12
+
13
+ class CollectionConfigKwargs(TypedDict, total=False):
14
+ """Configuration parameters for a vector collection.
15
+
16
+ These arguments are typically used when configuring connections to vector databases.
17
+ """
18
+
19
+ dimension: int | None
20
+ primary_field_name: str
21
+ id_type: str
22
+ vector_field_name: str
23
+ metric_type: str
24
+ timeout: float | None
25
+ schema: CollectionSchema | None
26
+ index_params: IndexParams | None
27
+
28
+
29
+ class FetchKwargs(TypedDict, total=False):
30
+ """Arguments for fetching data from vector collections.
31
+
32
+ Controls how data is retrieved from vector databases, including filtering
33
+ and result limiting parameters.
34
+ """
35
+
36
+ collection_name: str | None
37
+ similarity_threshold: float
38
+ result_per_query: int
39
+
40
+
41
+ class EmbeddingKwargs(TypedDict, total=False):
42
+ """Configuration parameters for text embedding operations.
43
+
44
+ These settings control the behavior of embedding models that convert text
45
+ to vector representations.
46
+ """
47
+
48
+ model: str
49
+ dimensions: int
50
+ timeout: int
51
+ caching: bool
52
+
53
+
54
+ class LLMKwargs(TypedDict, total=False):
55
+ """Configuration parameters for language model inference.
56
+
57
+ These arguments control the behavior of large language model calls,
58
+ including generation parameters and caching options.
59
+ """
60
+
61
+ model: str
62
+ temperature: float
63
+ stop: str | list[str]
64
+ top_p: float
65
+ max_tokens: int
66
+ stream: bool
67
+ timeout: int
68
+ max_retries: int
69
+ no_cache: bool # if the req uses cache in this call
70
+ no_store: bool # If store the response of this call to cache
71
+ cache_ttl: int # how long the stored cache is alive, in seconds
72
+ s_maxage: int # max accepted age of cached response, in seconds
73
+
74
+
75
+ class GenerateKwargs(LLMKwargs, total=False):
76
+ """Arguments for content generation operations.
77
+
78
+ Extends LLMKwargs with additional parameters specific to generation tasks,
79
+ such as the number of generated items and the system message.
80
+ """
81
+
82
+ system_message: str
83
+
84
+
85
+ class ValidateKwargs[T](GenerateKwargs, total=False):
86
+ """Arguments for content validation operations.
87
+
88
+ Extends LLMKwargs with additional parameters specific to validation tasks,
89
+ such as limiting the number of validation attempts.
90
+ """
91
+
92
+ default: T
93
+ max_validations: int
94
+ co_extractor: GenerateKwargs
95
+
96
+
97
+ # noinspection PyTypedDict
98
+ class ReviewKwargs[T](ValidateKwargs[T], total=False):
99
+ """Arguments for content review operations.
100
+
101
+ Extends GenerateKwargs with parameters for evaluating content against
102
+ specific topics and review criteria.
103
+ """
104
+
105
+ topic: Required[str]
106
+ criteria: set[str]
107
+
108
+
109
+ class CorrectKwargs[T](ReviewKwargs[T], total=False):
110
+ """Arguments for content correction operations.
111
+
112
+ Extends GenerateKwargs with parameters for correcting content based on
113
+ specific criteria and templates.
114
+ """
115
+
116
+ reference: str
117
+ supervisor_check: bool
118
+
119
+
120
+ # noinspection PyTypedDict
121
+ class ChooseKwargs[T](ValidateKwargs[T], total=False):
122
+ """Arguments for selection operations.
123
+
124
+ Extends GenerateKwargs with parameters for selecting among options,
125
+ such as the number of items to choose.
126
+ """
127
+
128
+ k: int
129
+
130
+
131
+ class CacheKwargs(TypedDict, total=False):
132
+ """Configuration parameters for the caching system.
133
+
134
+ These arguments control the behavior of various caching backends,
135
+ including in-memory, Redis, S3, and vector database caching options.
136
+ """
137
+
138
+ mode: CacheMode # when default_on cache is always on, when default_off cache is opt in
139
+ host: str
140
+ port: str
141
+ password: str
142
+ namespace: str
143
+ ttl: float
144
+ default_in_memory_ttl: float
145
+ default_in_redis_ttl: float
146
+ similarity_threshold: float
147
+ supported_call_types: list[CachingSupportedCallTypes]
148
+ # s3 Bucket, boto3 configuration
149
+ s3_bucket_name: str
150
+ s3_region_name: str
151
+ s3_api_version: str
152
+ s3_use_ssl: bool
153
+ s3_verify: bool | str
154
+ s3_endpoint_url: str
155
+ s3_aws_access_key_id: str
156
+ s3_aws_secret_access_key: str
157
+ s3_aws_session_token: str
158
+ s3_config: Any
159
+ s3_path: str
160
+ redis_semantic_cache_use_async: bool
161
+ redis_semantic_cache_embedding_model: str
162
+ redis_flush_size: int
163
+ redis_startup_nodes: list
164
+ disk_cache_dir: Any
165
+ qdrant_api_base: str
166
+ qdrant_api_key: str
167
+ qdrant_collection_name: str
168
+ qdrant_quantization_config: str
169
+ qdrant_semantic_cache_embedding_model: str
@@ -0,0 +1,72 @@
1
+ """Module that contains the Role class for managing workflows and their event registrations."""
2
+
3
+ from typing import Any, Self, Set
4
+
5
+ from fabricatio.capabilities.correct import Correct
6
+ from fabricatio.capabilities.task import HandleTask, ProposeTask
7
+ from fabricatio.core import env
8
+ from fabricatio.journal import logger
9
+ from fabricatio.models.action import WorkFlow
10
+ from fabricatio.models.events import Event
11
+ from fabricatio.models.tool import ToolBox
12
+ from pydantic import Field
13
+
14
+
15
+ class Role(ProposeTask, HandleTask, Correct):
16
+ """Class that represents a role with a registry of events and workflows.
17
+
18
+ A Role serves as a container for workflows, managing their registration to events
19
+ and providing them with shared configuration like tools and personality.
20
+
21
+ Attributes:
22
+ registry: Mapping of events to workflows that handle them
23
+ toolboxes: Set of toolboxes available to this role and its workflows
24
+ """
25
+
26
+ registry: dict[Event | str, WorkFlow] = Field(default_factory=dict)
27
+ """The registry of events and workflows."""
28
+
29
+ toolboxes: Set[ToolBox] = Field(default_factory=set)
30
+ """Collection of tools available to this role."""
31
+
32
+ def model_post_init(self, __context: Any) -> None:
33
+ """Initialize the role by resolving configurations and registering workflows.
34
+
35
+ Args:
36
+ __context: The context used for initialization
37
+ """
38
+ self.resolve_configuration().register_workflows()
39
+
40
+ def register_workflows(self) -> Self:
41
+ """Register each workflow in the registry to its corresponding event in the event bus.
42
+
43
+ Returns:
44
+ Self: The role instance for method chaining
45
+ """
46
+ for event, workflow in self.registry.items():
47
+ logger.debug(
48
+ f"Registering workflow: `{workflow.name}` for event: `{Event.instantiate_from(event).collapse()}`"
49
+ )
50
+ env.on(event, workflow.serve)
51
+ return self
52
+
53
+ def resolve_configuration(self) -> Self:
54
+ """Apply role-level configuration to all workflows in the registry.
55
+
56
+ This includes setting up fallback configurations, injecting personality traits,
57
+ and providing tool access to workflows and their steps.
58
+
59
+ Returns:
60
+ Self: The role instance for method chaining
61
+ """
62
+ for workflow in self.registry.values():
63
+ logger.debug(f"Resolving config for workflow: `{workflow.name}`")
64
+ (
65
+ workflow.fallback_to(self)
66
+ .steps_fallback_to_self()
67
+ .inject_personality(self.briefing)
68
+ .supply_tools_from(self)
69
+ .steps_supply_tools_from_self()
70
+ )
71
+
72
+ return self