fabricatio 0.2.0__cp312-cp312-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 +37 -0
- fabricatio/_rust.cp312-win_amd64.pyd +0 -0
- fabricatio/_rust.pyi +53 -0
- fabricatio/_rust_instances.py +8 -0
- fabricatio/actions/__init__.py +5 -0
- fabricatio/actions/communication.py +15 -0
- fabricatio/actions/transmission.py +23 -0
- fabricatio/config.py +263 -0
- fabricatio/core.py +167 -0
- fabricatio/decorators.py +178 -0
- fabricatio/fs/__init__.py +5 -0
- fabricatio/fs/curd.py +130 -0
- fabricatio/fs/readers.py +24 -0
- fabricatio/journal.py +28 -0
- fabricatio/models/action.py +139 -0
- fabricatio/models/advanced.py +128 -0
- fabricatio/models/events.py +82 -0
- fabricatio/models/generic.py +124 -0
- fabricatio/models/kwargs_types.py +26 -0
- fabricatio/models/role.py +48 -0
- fabricatio/models/task.py +276 -0
- fabricatio/models/tool.py +187 -0
- fabricatio/models/usages.py +515 -0
- fabricatio/models/utils.py +78 -0
- fabricatio/parser.py +93 -0
- fabricatio/py.typed +0 -0
- fabricatio/toolboxes/__init__.py +17 -0
- fabricatio/toolboxes/arithmetic.py +62 -0
- fabricatio/toolboxes/fs.py +15 -0
- fabricatio/toolboxes/task.py +6 -0
- fabricatio-0.2.0.data/scripts/tdown.exe +0 -0
- fabricatio-0.2.0.dist-info/METADATA +342 -0
- fabricatio-0.2.0.dist-info/RECORD +35 -0
- fabricatio-0.2.0.dist-info/WHEEL +4 -0
- fabricatio-0.2.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
"""The module containing the Event class."""
|
2
|
+
|
3
|
+
from typing import List, Self, Union
|
4
|
+
|
5
|
+
from fabricatio.config import configs
|
6
|
+
from pydantic import BaseModel, ConfigDict, Field
|
7
|
+
|
8
|
+
type EventLike = Union[str, List[str], "Event"]
|
9
|
+
|
10
|
+
|
11
|
+
class Event(BaseModel):
|
12
|
+
"""A class representing an event."""
|
13
|
+
|
14
|
+
model_config = ConfigDict(use_attribute_docstrings=True)
|
15
|
+
|
16
|
+
segments: List[str] = Field(default_factory=list, frozen=True)
|
17
|
+
""" The segments of the namespaces."""
|
18
|
+
|
19
|
+
@classmethod
|
20
|
+
def instantiate_from(cls, event: EventLike) -> Self:
|
21
|
+
"""Create an Event instance from a string or list of strings or an Event instance.
|
22
|
+
|
23
|
+
Args:
|
24
|
+
event (EventLike): The event to instantiate from.
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
Event: The Event instance.
|
28
|
+
"""
|
29
|
+
if isinstance(event, Event):
|
30
|
+
return event.clone()
|
31
|
+
if isinstance(event, str):
|
32
|
+
event = event.split(configs.pymitter.delimiter)
|
33
|
+
|
34
|
+
return cls(segments=event)
|
35
|
+
|
36
|
+
def derive(self, event: EventLike) -> Self:
|
37
|
+
"""Derive a new event from this event and another event or a string."""
|
38
|
+
return self.clone().concat(event)
|
39
|
+
|
40
|
+
def collapse(self) -> str:
|
41
|
+
"""Collapse the event into a string."""
|
42
|
+
return configs.pymitter.delimiter.join(self.segments)
|
43
|
+
|
44
|
+
def clone(self) -> Self:
|
45
|
+
"""Clone the event."""
|
46
|
+
return Event(segments=list(self.segments))
|
47
|
+
|
48
|
+
def push(self, segment: str) -> Self:
|
49
|
+
"""Push a segment to the event."""
|
50
|
+
if not segment:
|
51
|
+
raise ValueError("The segment must not be empty.")
|
52
|
+
if configs.pymitter.delimiter in segment:
|
53
|
+
raise ValueError("The segment must not contain the delimiter.")
|
54
|
+
|
55
|
+
self.segments.append(segment)
|
56
|
+
return self
|
57
|
+
|
58
|
+
def push_wildcard(self) -> Self:
|
59
|
+
"""Push a wildcard segment to the event."""
|
60
|
+
return self.push("*")
|
61
|
+
|
62
|
+
def pop(self) -> str:
|
63
|
+
"""Pop a segment from the event."""
|
64
|
+
return self.segments.pop()
|
65
|
+
|
66
|
+
def clear(self) -> Self:
|
67
|
+
"""Clear the event."""
|
68
|
+
self.segments.clear()
|
69
|
+
return self
|
70
|
+
|
71
|
+
def concat(self, event: EventLike) -> Self:
|
72
|
+
"""Concatenate another event to this event."""
|
73
|
+
self.segments.extend(Event.instantiate_from(event).segments)
|
74
|
+
return self
|
75
|
+
|
76
|
+
def __hash__(self) -> int:
|
77
|
+
"""Return the hash of the event, using the collapsed string."""
|
78
|
+
return hash(self.collapse())
|
79
|
+
|
80
|
+
def __eq__(self, other: str | List[str] | Self) -> bool:
|
81
|
+
"""Check if the event is equal to another event or a string."""
|
82
|
+
return self.collapse() == Event.instantiate_from(other).collapse()
|
@@ -0,0 +1,124 @@
|
|
1
|
+
"""This module defines generic classes for models in the Fabricatio library."""
|
2
|
+
|
3
|
+
from pathlib import Path
|
4
|
+
from typing import List, Self
|
5
|
+
|
6
|
+
import orjson
|
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
|
11
|
+
from pydantic import (
|
12
|
+
BaseModel,
|
13
|
+
ConfigDict,
|
14
|
+
Field,
|
15
|
+
)
|
16
|
+
|
17
|
+
|
18
|
+
class Base(BaseModel):
|
19
|
+
"""Base class for all models with Pydantic configuration."""
|
20
|
+
|
21
|
+
model_config = ConfigDict(use_attribute_docstrings=True)
|
22
|
+
|
23
|
+
|
24
|
+
class Named(Base):
|
25
|
+
"""Class that includes a name attribute."""
|
26
|
+
|
27
|
+
name: str = Field(frozen=True)
|
28
|
+
"""The name of the object."""
|
29
|
+
|
30
|
+
|
31
|
+
class Described(Base):
|
32
|
+
"""Class that includes a description attribute."""
|
33
|
+
|
34
|
+
description: str = Field(default="", frozen=True)
|
35
|
+
"""The description of the object."""
|
36
|
+
|
37
|
+
|
38
|
+
class WithBriefing(Named, Described):
|
39
|
+
"""Class that provides a briefing based on the name and description."""
|
40
|
+
|
41
|
+
@property
|
42
|
+
def briefing(self) -> str:
|
43
|
+
"""Get the briefing of the object.
|
44
|
+
|
45
|
+
Returns:
|
46
|
+
str: The briefing of the object.
|
47
|
+
"""
|
48
|
+
return f"{self.name}: {self.description}" if self.description else self.name
|
49
|
+
|
50
|
+
|
51
|
+
class WithJsonExample(Base):
|
52
|
+
"""Class that provides a JSON schema for the model."""
|
53
|
+
|
54
|
+
@classmethod
|
55
|
+
def json_example(cls) -> str:
|
56
|
+
"""Return a JSON example for the model.
|
57
|
+
|
58
|
+
Returns:
|
59
|
+
str: A JSON example for the model.
|
60
|
+
"""
|
61
|
+
return orjson.dumps(
|
62
|
+
{field_name: field_info.description for field_name, field_info in cls.model_fields.items()},
|
63
|
+
option=orjson.OPT_INDENT_2 | orjson.OPT_SORT_KEYS,
|
64
|
+
).decode()
|
65
|
+
|
66
|
+
|
67
|
+
class WithDependency(Base):
|
68
|
+
"""Class that manages file dependencies."""
|
69
|
+
|
70
|
+
dependencies: List[str] = Field(default_factory=list)
|
71
|
+
"""The file dependencies which is needed to read or write to meet a specific requirement, a list of file paths."""
|
72
|
+
|
73
|
+
def add_dependency[P: str | Path](self, dependency: P | List[P]) -> Self:
|
74
|
+
"""Add a file dependency to the task.
|
75
|
+
|
76
|
+
Args:
|
77
|
+
dependency (str | Path | List[str | Path]): The file dependency to add to the task.
|
78
|
+
|
79
|
+
Returns:
|
80
|
+
Self: The current instance of the task.
|
81
|
+
"""
|
82
|
+
if not isinstance(dependency, list):
|
83
|
+
dependency = [dependency]
|
84
|
+
self.dependencies.extend(Path(d).as_posix() for d in dependency)
|
85
|
+
return self
|
86
|
+
|
87
|
+
def remove_dependency[P: str | Path](self, dependency: P | List[P]) -> Self:
|
88
|
+
"""Remove a file dependency from the task.
|
89
|
+
|
90
|
+
Args:
|
91
|
+
dependency (str | Path | List[str | Path]): The file dependency to remove from the task.
|
92
|
+
|
93
|
+
Returns:
|
94
|
+
Self: The current instance of the task.
|
95
|
+
"""
|
96
|
+
if not isinstance(dependency, list):
|
97
|
+
dependency = [dependency]
|
98
|
+
for d in dependency:
|
99
|
+
self.dependencies.remove(Path(d).as_posix())
|
100
|
+
return self
|
101
|
+
|
102
|
+
@property
|
103
|
+
def dependencies_prompt(self) -> str:
|
104
|
+
"""Generate a prompt for the task based on the file dependencies.
|
105
|
+
|
106
|
+
Returns:
|
107
|
+
str: The generated prompt for the task.
|
108
|
+
"""
|
109
|
+
return template_manager.render_template(
|
110
|
+
configs.templates.dependencies_template,
|
111
|
+
{
|
112
|
+
(pth := Path(p)).name: {
|
113
|
+
"path": pth.as_posix(),
|
114
|
+
"exists": pth.exists(),
|
115
|
+
"description": (identity := magika.identify_path(pth)).output.description,
|
116
|
+
"size": f"{pth.stat().st_size / (1024 * 1024) if pth.exists() and pth.is_file() else 0:.3f} MB",
|
117
|
+
"content": (text := safe_text_read(pth)),
|
118
|
+
"lines": len(text.splitlines()),
|
119
|
+
"language": identity.output.ct_label,
|
120
|
+
"checksum": blake3_hash(pth.read_bytes()) if pth.exists() and pth.is_file() else "unknown",
|
121
|
+
}
|
122
|
+
for p in self.dependencies
|
123
|
+
},
|
124
|
+
)
|
@@ -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]
|
@@ -0,0 +1,48 @@
|
|
1
|
+
"""Module that contains the Role class."""
|
2
|
+
|
3
|
+
from typing import Any, Self, Set
|
4
|
+
|
5
|
+
from fabricatio.core import env
|
6
|
+
from fabricatio.journal import logger
|
7
|
+
from fabricatio.models.action import WorkFlow
|
8
|
+
from fabricatio.models.advanced import ProposeTask
|
9
|
+
from fabricatio.models.events import Event
|
10
|
+
from fabricatio.models.tool import ToolBox
|
11
|
+
from fabricatio.models.usages import ToolBoxUsage
|
12
|
+
from pydantic import Field
|
13
|
+
|
14
|
+
|
15
|
+
class Role(ProposeTask, ToolBoxUsage):
|
16
|
+
"""Class that represents a role with a registry of events and workflows."""
|
17
|
+
|
18
|
+
registry: dict[Event | str, WorkFlow] = Field(...)
|
19
|
+
""" The registry of events and workflows."""
|
20
|
+
|
21
|
+
toolboxes: Set[ToolBox] = Field(default_factory=set)
|
22
|
+
|
23
|
+
def model_post_init(self, __context: Any) -> None:
|
24
|
+
"""Register the workflows in the role to the event bus."""
|
25
|
+
self.resolve_configuration().register_workflows()
|
26
|
+
|
27
|
+
def register_workflows(self) -> Self:
|
28
|
+
"""Register the workflows in the role to the event bus."""
|
29
|
+
for event, workflow in self.registry.items():
|
30
|
+
logger.debug(
|
31
|
+
f"Registering workflow: `{workflow.name}` for event: `{Event.instantiate_from(event).collapse()}`"
|
32
|
+
)
|
33
|
+
env.on(event, workflow.serve)
|
34
|
+
return self
|
35
|
+
|
36
|
+
def resolve_configuration(self) -> Self:
|
37
|
+
"""Resolve the configuration of the role."""
|
38
|
+
for workflow in self.registry.values():
|
39
|
+
logger.debug(f"Resolving config for workflow: `{workflow.name}`")
|
40
|
+
(
|
41
|
+
workflow.fallback_to(self)
|
42
|
+
.steps_fallback_to_self()
|
43
|
+
.inject_personality(self.briefing)
|
44
|
+
.supply_tools_from(self)
|
45
|
+
.steps_supply_tools_from_self()
|
46
|
+
)
|
47
|
+
|
48
|
+
return self
|
@@ -0,0 +1,276 @@
|
|
1
|
+
"""This module defines the `Task` class, which represents a task with a status and output.
|
2
|
+
|
3
|
+
It includes methods to manage the task's lifecycle, such as starting, finishing, cancelling, and failing the task.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from asyncio import Queue
|
7
|
+
from enum import Enum
|
8
|
+
from typing import Any, List, Optional, Self
|
9
|
+
|
10
|
+
from fabricatio._rust_instances import template_manager
|
11
|
+
from fabricatio.config import configs
|
12
|
+
from fabricatio.core import env
|
13
|
+
from fabricatio.journal import logger
|
14
|
+
from fabricatio.models.events import Event, EventLike
|
15
|
+
from fabricatio.models.generic import WithBriefing, WithDependency, WithJsonExample
|
16
|
+
from pydantic import Field, PrivateAttr
|
17
|
+
|
18
|
+
|
19
|
+
class TaskStatus(Enum):
|
20
|
+
"""An enumeration representing the status of a task.
|
21
|
+
|
22
|
+
Attributes:
|
23
|
+
Pending: The task is pending.
|
24
|
+
Running: The task is currently running.
|
25
|
+
Finished: The task has been successfully completed.
|
26
|
+
Failed: The task has failed.
|
27
|
+
Cancelled: The task has been cancelled.
|
28
|
+
"""
|
29
|
+
|
30
|
+
Pending = "pending"
|
31
|
+
Running = "running"
|
32
|
+
Finished = "finished"
|
33
|
+
Failed = "failed"
|
34
|
+
Cancelled = "cancelled"
|
35
|
+
|
36
|
+
|
37
|
+
class Task[T](WithBriefing, WithJsonExample, WithDependency):
|
38
|
+
"""A class representing a task with a status and output.
|
39
|
+
|
40
|
+
Attributes:
|
41
|
+
name (str): The name of the task.
|
42
|
+
description (str): The description of the task.
|
43
|
+
goal (str): The goal of the task.
|
44
|
+
dependencies (List[str]): The file dependencies of the task, a list of file paths.
|
45
|
+
namespace (List[str]): The namespace of the task, a list of namespace segment, as string.
|
46
|
+
"""
|
47
|
+
|
48
|
+
name: str = Field(...)
|
49
|
+
"""The name of the task."""
|
50
|
+
|
51
|
+
description: str = Field(default="")
|
52
|
+
"""The description of the task."""
|
53
|
+
|
54
|
+
goal: List[str] = Field(default=[])
|
55
|
+
"""The goal of the task, a list of strings."""
|
56
|
+
|
57
|
+
namespace: List[str] = Field(default_factory=list)
|
58
|
+
"""The namespace of the task, a list of namespace segment, as string."""
|
59
|
+
|
60
|
+
_output: Queue = PrivateAttr(default_factory=lambda: Queue(maxsize=1))
|
61
|
+
"""The output queue of the task."""
|
62
|
+
|
63
|
+
_status: TaskStatus = PrivateAttr(default=TaskStatus.Pending)
|
64
|
+
"""The status of the task."""
|
65
|
+
|
66
|
+
_namespace: Event = PrivateAttr(default_factory=Event)
|
67
|
+
"""The namespace of the task as an event, which is generated from the namespace list."""
|
68
|
+
|
69
|
+
def model_post_init(self, __context: Any) -> None:
|
70
|
+
"""Initialize the task with a namespace event."""
|
71
|
+
self._namespace.segments.extend(self.namespace)
|
72
|
+
|
73
|
+
def move_to(self, new_namespace: EventLike) -> Self:
|
74
|
+
"""Move the task to a new namespace.
|
75
|
+
|
76
|
+
Args:
|
77
|
+
new_namespace (EventLike): The new namespace to move the task to.
|
78
|
+
|
79
|
+
Returns:
|
80
|
+
Task: The moved instance of the `Task` class.
|
81
|
+
"""
|
82
|
+
logger.debug(f"Moving task `{self.name}` to `{new_namespace}`")
|
83
|
+
self._namespace.clear().concat(new_namespace)
|
84
|
+
self.namespace = self._namespace.segments
|
85
|
+
return self
|
86
|
+
|
87
|
+
def nested_move_to(self, new_parent_namespace: EventLike) -> Self:
|
88
|
+
"""Move the task to a new namespace by nesting it under the new parent namespace.
|
89
|
+
|
90
|
+
Args:
|
91
|
+
new_parent_namespace (EventLike): The new parent namespace to move the task to.
|
92
|
+
|
93
|
+
Returns:
|
94
|
+
Task: The nested moved instance of the `Task` class.
|
95
|
+
"""
|
96
|
+
logger.debug(f"Nested moving task `{self.name}` to `{new_parent_namespace}`")
|
97
|
+
self._namespace.clear().concat(new_parent_namespace).concat(self.namespace)
|
98
|
+
self.namespace = self._namespace.segments
|
99
|
+
return self
|
100
|
+
|
101
|
+
@classmethod
|
102
|
+
def simple_task(cls, name: str, goal: str, description: str) -> Self:
|
103
|
+
"""Create a simple task with a name, goal, and description.
|
104
|
+
|
105
|
+
Args:
|
106
|
+
name (str): The name of the task.
|
107
|
+
goal (str): The goal of the task.
|
108
|
+
description (str): The description of the task.
|
109
|
+
|
110
|
+
Returns:
|
111
|
+
Task: A new instance of the `Task` class.
|
112
|
+
"""
|
113
|
+
return cls(name=name, goal=goal, description=description)
|
114
|
+
|
115
|
+
def update_task(self, goal: Optional[str] = None, description: Optional[str] = None) -> Self:
|
116
|
+
"""Update the goal and description of the task.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
goal (str, optional): The new goal of the task.
|
120
|
+
description (str, optional): The new description of the task.
|
121
|
+
|
122
|
+
Returns:
|
123
|
+
Task: The updated instance of the `Task` class.
|
124
|
+
"""
|
125
|
+
if goal:
|
126
|
+
self.goal = goal
|
127
|
+
if description:
|
128
|
+
self.description = description
|
129
|
+
return self
|
130
|
+
|
131
|
+
async def get_output(self) -> T:
|
132
|
+
"""Get the output of the task.
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
T: The output of the task.
|
136
|
+
"""
|
137
|
+
logger.debug(f"Getting output for task {self.name}")
|
138
|
+
return await self._output.get()
|
139
|
+
|
140
|
+
def status_label(self, status: TaskStatus) -> str:
|
141
|
+
"""Return a formatted status label for the task.
|
142
|
+
|
143
|
+
Args:
|
144
|
+
status (TaskStatus): The status of the task.
|
145
|
+
|
146
|
+
Returns:
|
147
|
+
str: The formatted status label.
|
148
|
+
"""
|
149
|
+
return self._namespace.derive(self.name).push(status.value).collapse()
|
150
|
+
|
151
|
+
@property
|
152
|
+
def pending_label(self) -> str:
|
153
|
+
"""Return the pending status label for the task.
|
154
|
+
|
155
|
+
Returns:
|
156
|
+
str: The pending status label.
|
157
|
+
"""
|
158
|
+
return self.status_label(TaskStatus.Pending)
|
159
|
+
|
160
|
+
@property
|
161
|
+
def running_label(self) -> str:
|
162
|
+
"""Return the running status label for the task.
|
163
|
+
|
164
|
+
Returns:
|
165
|
+
str: The running status label.
|
166
|
+
"""
|
167
|
+
return self.status_label(TaskStatus.Running)
|
168
|
+
|
169
|
+
@property
|
170
|
+
def finished_label(self) -> str:
|
171
|
+
"""Return the finished status label for the task.
|
172
|
+
|
173
|
+
Returns:
|
174
|
+
str: The finished status label.
|
175
|
+
"""
|
176
|
+
return self.status_label(TaskStatus.Finished)
|
177
|
+
|
178
|
+
@property
|
179
|
+
def failed_label(self) -> str:
|
180
|
+
"""Return the failed status label for the task.
|
181
|
+
|
182
|
+
Returns:
|
183
|
+
str: The failed status label.
|
184
|
+
"""
|
185
|
+
return self.status_label(TaskStatus.Failed)
|
186
|
+
|
187
|
+
@property
|
188
|
+
def cancelled_label(self) -> str:
|
189
|
+
"""Return the cancelled status label for the task.
|
190
|
+
|
191
|
+
Returns:
|
192
|
+
str: The cancelled status label.
|
193
|
+
"""
|
194
|
+
return self.status_label(TaskStatus.Cancelled)
|
195
|
+
|
196
|
+
async def finish(self, output: T) -> Self:
|
197
|
+
"""Mark the task as finished and set the output.
|
198
|
+
|
199
|
+
Args:
|
200
|
+
output (T): The output of the task.
|
201
|
+
|
202
|
+
Returns:
|
203
|
+
Task: The finished instance of the `Task` class.
|
204
|
+
"""
|
205
|
+
logger.info(f"Finishing task {self.name}")
|
206
|
+
self._status = TaskStatus.Finished
|
207
|
+
await self._output.put(output)
|
208
|
+
logger.debug(f"Output set for task {self.name}")
|
209
|
+
await env.emit_async(self.finished_label, self)
|
210
|
+
logger.debug(f"Emitted finished event for task {self.name}")
|
211
|
+
return self
|
212
|
+
|
213
|
+
async def start(self) -> Self:
|
214
|
+
"""Mark the task as running.
|
215
|
+
|
216
|
+
Returns:
|
217
|
+
Task: The running instance of the `Task` class.
|
218
|
+
"""
|
219
|
+
logger.info(f"Starting task `{self.name}`")
|
220
|
+
self._status = TaskStatus.Running
|
221
|
+
await env.emit_async(self.running_label, self)
|
222
|
+
return self
|
223
|
+
|
224
|
+
async def cancel(self) -> Self:
|
225
|
+
"""Mark the task as cancelled.
|
226
|
+
|
227
|
+
Returns:
|
228
|
+
Task: The cancelled instance of the `Task` class.
|
229
|
+
"""
|
230
|
+
logger.info(f"Cancelling task `{self.name}`")
|
231
|
+
self._status = TaskStatus.Cancelled
|
232
|
+
await env.emit_async(self.cancelled_label, self)
|
233
|
+
return self
|
234
|
+
|
235
|
+
async def fail(self) -> Self:
|
236
|
+
"""Mark the task as failed.
|
237
|
+
|
238
|
+
Returns:
|
239
|
+
Task: The failed instance of the `Task` class.
|
240
|
+
"""
|
241
|
+
logger.info(f"Failing task `{self.name}`")
|
242
|
+
self._status = TaskStatus.Failed
|
243
|
+
await env.emit_async(self.failed_label, self)
|
244
|
+
return self
|
245
|
+
|
246
|
+
async def publish(self) -> Self:
|
247
|
+
"""Publish the task to the event bus.
|
248
|
+
|
249
|
+
Returns:
|
250
|
+
Task: The published instance of the `Task` class
|
251
|
+
"""
|
252
|
+
logger.info(f"Publishing task `{(label := self.pending_label)}`")
|
253
|
+
await env.emit_async(label, self)
|
254
|
+
return self
|
255
|
+
|
256
|
+
async def delegate(self) -> T:
|
257
|
+
"""Delegate the task to the event bus and wait for the output.
|
258
|
+
|
259
|
+
Returns:
|
260
|
+
T: The output of the task
|
261
|
+
"""
|
262
|
+
logger.info(f"Delegating task `{(label := self.pending_label)}`")
|
263
|
+
await env.emit_async(label, self)
|
264
|
+
return await self.get_output()
|
265
|
+
|
266
|
+
@property
|
267
|
+
def briefing(self) -> str:
|
268
|
+
"""Return a briefing of the task including its goal.
|
269
|
+
|
270
|
+
Returns:
|
271
|
+
str: The briefing of the task.
|
272
|
+
"""
|
273
|
+
return template_manager.render_template(
|
274
|
+
configs.templates.task_briefing_template,
|
275
|
+
self.model_dump(),
|
276
|
+
)
|