fabricatio 0.2.2__tar.gz → 0.2.3.dev1__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.2 → fabricatio-0.2.3.dev1}/PKG-INFO +1 -1
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/examples/task_handle/handle_task.py +43 -7
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/pyproject.toml +1 -1
- fabricatio-0.2.3.dev1/python/fabricatio/capabilities/rag.py +46 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/config.py +17 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/core.py +33 -19
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/models/action.py +6 -2
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/models/kwargs_types.py +9 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/models/task.py +61 -9
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/models/usages.py +94 -2
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/models/utils.py +50 -1
- fabricatio-0.2.3.dev1/templates.tar.gz +0 -0
- fabricatio-0.2.3.dev1/uv.lock +1573 -0
- fabricatio-0.2.2/templates.tar.gz +0 -0
- fabricatio-0.2.2/uv.lock +0 -1573
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/.github/workflows/build-package.yaml +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/.github/workflows/ruff.yaml +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/.github/workflows/tests.yaml +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/.gitignore +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/.python-version +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/Cargo.lock +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/Cargo.toml +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/LICENSE +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/Makefile +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/README.md +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/examples/llm_usages/llm_usage.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/examples/make_a_rating/rating.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/examples/make_diary/commits.json +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/examples/make_diary/diary.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/examples/minor/hello_fabricatio.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/examples/propose_task/propose.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/examples/simple_chat/chat.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/__init__.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/_rust.pyi +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/_rust_instances.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/actions/__init__.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/actions/communication.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/actions/transmission.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/capabilities/rating.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/capabilities/task.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/decorators.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/fs/__init__.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/fs/curd.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/fs/readers.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/journal.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/models/events.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/models/generic.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/models/role.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/models/tool.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/parser.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/py.typed +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/toolboxes/__init__.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/toolboxes/arithmetic.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/toolboxes/fs.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/python/fabricatio/toolboxes/task.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/src/hash.rs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/src/lib.rs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/src/templates.rs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/binary-exploitation-ctf-solver.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/claude-xml.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/clean-up-code.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/cryptography-ctf-solver.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/dependencies.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/document-the-code.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/draft_rating_criteria.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/draft_rating_manual.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/draft_rating_weights_klee.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/draft_tool_usage_code.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/extract_criteria_from_reasons.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/extract_reasons_from_examples.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/find-security-vulnerabilities.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/fix-bugs.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/improve-performance.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/make_choice.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/make_judgment.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/propose_task.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/rate_fine_grind.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/refactor.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/reverse-engineering-ctf-solver.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/task_briefing.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/web-ctf-solver.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/write-git-commit.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/write-github-pull-request.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/templates/built-in/write-github-readme.hbs +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/tests/test_config.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/tests/test_models/test_action.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/tests/test_models/test_advanced.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/tests/test_models/test_generic.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/tests/test_models/test_role.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/tests/test_models/test_task.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/tests/test_models/test_tool.py +0 -0
- {fabricatio-0.2.2 → fabricatio-0.2.3.dev1}/tests/test_models/test_usages.py +0 -0
@@ -56,6 +56,30 @@ class WriteDocumentation(Action):
|
|
56
56
|
return await self.aask(task_input.briefing, system_message=task_input.dependencies_prompt)
|
57
57
|
|
58
58
|
|
59
|
+
class TestCancel(Action):
|
60
|
+
"""Action that says hello to the world."""
|
61
|
+
|
62
|
+
name: str = "cancel"
|
63
|
+
description: str = "cancel the task"
|
64
|
+
output_key: str = "counter"
|
65
|
+
|
66
|
+
async def _execute(self, counter: int, **_) -> int:
|
67
|
+
logger.info(f"Counter: {counter}")
|
68
|
+
await asyncio.sleep(5)
|
69
|
+
counter += 1
|
70
|
+
return counter
|
71
|
+
|
72
|
+
|
73
|
+
class WriteToOutput(Action):
|
74
|
+
"""Action that says hello to the world."""
|
75
|
+
|
76
|
+
name: str = "write to output"
|
77
|
+
output_key: str = "task_output"
|
78
|
+
|
79
|
+
async def _execute(self, **_) -> str:
|
80
|
+
return "hi, this is the output"
|
81
|
+
|
82
|
+
|
59
83
|
async def main() -> None:
|
60
84
|
"""Main function."""
|
61
85
|
role = Role(
|
@@ -68,20 +92,32 @@ async def main() -> None:
|
|
68
92
|
Event.instantiate_from("doc").push_wildcard().push("pending"): WorkFlow(
|
69
93
|
name="write documentation", steps=(WriteDocumentation, DumpText)
|
70
94
|
),
|
95
|
+
Event.instantiate_from("cancel_test").push_wildcard().push("pending"): WorkFlow(
|
96
|
+
name="cancel_test",
|
97
|
+
steps=(TestCancel, TestCancel, TestCancel, TestCancel, TestCancel, TestCancel, WriteToOutput),
|
98
|
+
extra_init_context={"counter": 0},
|
99
|
+
),
|
71
100
|
},
|
72
101
|
)
|
73
102
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
path = await proposed_task.
|
103
|
+
proposed_task = await role.propose(
|
104
|
+
"i want you to write a cli app implemented with python , which can calculate the sum to a given n, all write to a single file names `cli.py`, put it in `output` folder."
|
105
|
+
)
|
106
|
+
path = await proposed_task.delegate("coding")
|
78
107
|
logger.success(f"Code Path: {path}")
|
79
108
|
|
80
|
-
proposed_task = await role.propose(
|
81
|
-
|
82
|
-
|
109
|
+
proposed_task = await role.propose(
|
110
|
+
f"write Readme.md file for the code, source file {path},save it in `README.md`,which is in the `output` folder, too."
|
111
|
+
)
|
112
|
+
proposed_task.override_dependencies(path)
|
113
|
+
doc = await proposed_task.delegate("doc")
|
83
114
|
logger.success(f"Documentation: \n{doc}")
|
84
115
|
|
116
|
+
proposed_task.publish("cancel_test")
|
117
|
+
await proposed_task.cancel()
|
118
|
+
out = await proposed_task.get_output()
|
119
|
+
logger.info(f"Canceled Task Output: {out}")
|
120
|
+
|
85
121
|
|
86
122
|
if __name__ == "__main__":
|
87
123
|
asyncio.run(main())
|
@@ -0,0 +1,46 @@
|
|
1
|
+
"""A module for the RAG (Retrieval Augmented Generation) model."""
|
2
|
+
|
3
|
+
from typing import Any, Dict, List, Optional, Self, Union
|
4
|
+
|
5
|
+
from fabricatio.config import configs
|
6
|
+
from fabricatio.models.utils import MilvusData
|
7
|
+
|
8
|
+
try:
|
9
|
+
from pymilvus import MilvusClient
|
10
|
+
except ImportError as e:
|
11
|
+
raise RuntimeError("pymilvus is not installed. Have you installed `fabricatio[rag]` instead of `fabricatio`") from e
|
12
|
+
from pydantic import BaseModel, ConfigDict, PrivateAttr
|
13
|
+
|
14
|
+
|
15
|
+
class Rag(BaseModel):
|
16
|
+
"""A class representing the RAG (Retrieval Augmented Generation) model."""
|
17
|
+
|
18
|
+
model_config = ConfigDict(use_attribute_docstrings=True)
|
19
|
+
|
20
|
+
_client: MilvusClient = PrivateAttr(
|
21
|
+
default=MilvusClient(
|
22
|
+
uri=configs.rag.milvus_uri.unicode_string(),
|
23
|
+
token=configs.rag.milvus_token.get_secret_value(),
|
24
|
+
timeout=configs.rag.milvus_timeout,
|
25
|
+
),
|
26
|
+
)
|
27
|
+
_target_collection: Optional[str] = PrivateAttr(default=None)
|
28
|
+
|
29
|
+
@property
|
30
|
+
def client(self) -> MilvusClient:
|
31
|
+
"""The Milvus client."""
|
32
|
+
return self._client
|
33
|
+
|
34
|
+
def add_document[D: Union[Dict[str, Any] | MilvusData]](self, collection_name: str, data: D | List[D]) -> Self:
|
35
|
+
"""Adds a document to the specified collection.
|
36
|
+
|
37
|
+
Args:
|
38
|
+
collection_name (str): The name of the collection.
|
39
|
+
data (dict): The data to be added to the collection.
|
40
|
+
"""
|
41
|
+
if isinstance(data, MilvusData):
|
42
|
+
data = data.prepare_insertion()
|
43
|
+
if isinstance(data, list):
|
44
|
+
data = [d.prepare_insertion() if isinstance(d, MilvusData) else d for d in data]
|
45
|
+
self.client.insert(collection_name, data)
|
46
|
+
return self
|
@@ -11,6 +11,7 @@ from pydantic import (
|
|
11
11
|
FilePath,
|
12
12
|
HttpUrl,
|
13
13
|
NonNegativeFloat,
|
14
|
+
PositiveFloat,
|
14
15
|
PositiveInt,
|
15
16
|
SecretStr,
|
16
17
|
)
|
@@ -207,6 +208,19 @@ class ToolBoxConfig(BaseModel):
|
|
207
208
|
"""The name of the module containing the data."""
|
208
209
|
|
209
210
|
|
211
|
+
class RagConfig(BaseModel):
|
212
|
+
"""RAG configuration class."""
|
213
|
+
|
214
|
+
model_config = ConfigDict(use_attribute_docstrings=True)
|
215
|
+
|
216
|
+
milvus_uri: HttpUrl = Field(default=HttpUrl("http://localhost:19530"))
|
217
|
+
"""The URI of the Milvus server."""
|
218
|
+
milvus_timeout: Optional[PositiveFloat] = Field(default=None)
|
219
|
+
"""The timeout of the Milvus server."""
|
220
|
+
milvus_token: Optional[SecretStr] = Field(default=None)
|
221
|
+
"""The token of the Milvus server."""
|
222
|
+
|
223
|
+
|
210
224
|
class Settings(BaseSettings):
|
211
225
|
"""Application settings class.
|
212
226
|
|
@@ -250,6 +264,9 @@ class Settings(BaseSettings):
|
|
250
264
|
toolbox: ToolBoxConfig = Field(default_factory=ToolBoxConfig)
|
251
265
|
"""Toolbox Configuration"""
|
252
266
|
|
267
|
+
rag: RagConfig = Field(default_factory=RagConfig)
|
268
|
+
"""RAG Configuration"""
|
269
|
+
|
253
270
|
@classmethod
|
254
271
|
def settings_customise_sources(
|
255
272
|
cls,
|
@@ -38,11 +38,11 @@ class Env(BaseModel):
|
|
38
38
|
|
39
39
|
@overload
|
40
40
|
def on[**P, R](
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
41
|
+
self,
|
42
|
+
event: str | Event,
|
43
|
+
func: Optional[Callable[P, R]] = None,
|
44
|
+
/,
|
45
|
+
ttl: int = -1,
|
46
46
|
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
47
47
|
"""
|
48
48
|
Registers an event listener with a specific function that listens indefinitely or for a specified number of times.
|
@@ -58,11 +58,11 @@ class Env(BaseModel):
|
|
58
58
|
...
|
59
59
|
|
60
60
|
def on[**P, R](
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
61
|
+
self,
|
62
|
+
event: str | Event,
|
63
|
+
func: Optional[Callable[P, R]] = None,
|
64
|
+
/,
|
65
|
+
ttl=-1,
|
66
66
|
) -> Callable[[Callable[P, R]], Callable[P, R]] | Self:
|
67
67
|
"""Registers an event listener with a specific function that listens indefinitely or for a specified number of times.
|
68
68
|
|
@@ -78,14 +78,13 @@ class Env(BaseModel):
|
|
78
78
|
event = event.collapse()
|
79
79
|
if func is None:
|
80
80
|
return self._ee.on(event, ttl=ttl)
|
81
|
-
|
82
81
|
self._ee.on(event, func, ttl=ttl)
|
83
82
|
return self
|
84
83
|
|
85
84
|
@overload
|
86
85
|
def once[**P, R](
|
87
|
-
|
88
|
-
|
86
|
+
self,
|
87
|
+
event: str | Event,
|
89
88
|
) -> Callable[[Callable[P, R]], Callable[P, R]]:
|
90
89
|
"""
|
91
90
|
Registers an event listener that listens only once.
|
@@ -100,9 +99,9 @@ class Env(BaseModel):
|
|
100
99
|
|
101
100
|
@overload
|
102
101
|
def once[**P, R](
|
103
|
-
|
104
|
-
|
105
|
-
|
102
|
+
self,
|
103
|
+
event: str | Event,
|
104
|
+
func: Callable[[Callable[P, R]], Callable[P, R]],
|
106
105
|
) -> Self:
|
107
106
|
"""
|
108
107
|
Registers an event listener with a specific function that listens only once.
|
@@ -117,9 +116,9 @@ class Env(BaseModel):
|
|
117
116
|
...
|
118
117
|
|
119
118
|
def once[**P, R](
|
120
|
-
|
121
|
-
|
122
|
-
|
119
|
+
self,
|
120
|
+
event: str | Event,
|
121
|
+
func: Optional[Callable[P, R]] = None,
|
123
122
|
) -> Callable[[Callable[P, R]], Callable[P, R]] | Self:
|
124
123
|
"""Registers an event listener with a specific function that listens only once.
|
125
124
|
|
@@ -163,5 +162,20 @@ class Env(BaseModel):
|
|
163
162
|
event = event.collapse()
|
164
163
|
return await self._ee.emit_async(event, *args, **kwargs)
|
165
164
|
|
165
|
+
def emit_future[**P](self, event: str | Event, *args: P.args, **kwargs: P.kwargs) -> None:
|
166
|
+
"""Emits an event to all registered listeners and returns a future object.
|
167
|
+
|
168
|
+
Args:
|
169
|
+
event (str | Event): The event to emit.
|
170
|
+
*args: Positional arguments to pass to the listeners.
|
171
|
+
**kwargs: Keyword arguments to pass to the listeners.
|
172
|
+
|
173
|
+
Returns:
|
174
|
+
None: The future object.
|
175
|
+
"""
|
176
|
+
if isinstance(event, Event):
|
177
|
+
event = event.collapse()
|
178
|
+
return self._ee.emit_future(event, *args, **kwargs)
|
179
|
+
|
166
180
|
|
167
181
|
env = Env()
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
import traceback
|
4
4
|
from abc import abstractmethod
|
5
|
-
from asyncio import Queue
|
5
|
+
from asyncio import Queue, create_task
|
6
6
|
from typing import Any, Dict, Self, Tuple, Type, Union, Unpack
|
7
7
|
|
8
8
|
from fabricatio.capabilities.rating import GiveRating
|
@@ -108,7 +108,11 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
|
|
108
108
|
try:
|
109
109
|
for step in self._instances:
|
110
110
|
logger.debug(f"Executing step: {step.name}")
|
111
|
-
|
111
|
+
act_task = create_task(step.act(await self._context.get()))
|
112
|
+
if task.is_cancelled():
|
113
|
+
act_task.cancel(f"Cancelled by task: {task.name}")
|
114
|
+
break
|
115
|
+
modified_ctx = await act_task
|
112
116
|
await self._context.put(modified_ctx)
|
113
117
|
current_action = step.name
|
114
118
|
logger.info(f"Finished executing workflow: {self.name}")
|
@@ -5,6 +5,15 @@ from typing import List, NotRequired, TypedDict
|
|
5
5
|
from pydantic import NonNegativeFloat, NonNegativeInt, PositiveInt
|
6
6
|
|
7
7
|
|
8
|
+
class EmbeddingKwargs(TypedDict):
|
9
|
+
"""A type representing the keyword arguments for the embedding method."""
|
10
|
+
|
11
|
+
model: NotRequired[str]
|
12
|
+
dimensions: NotRequired[int]
|
13
|
+
timeout: NotRequired[PositiveInt]
|
14
|
+
caching: NotRequired[bool]
|
15
|
+
|
16
|
+
|
8
17
|
class LLMKwargs(TypedDict):
|
9
18
|
"""A type representing the keyword arguments for the LLM (Large Language Model) usage."""
|
10
19
|
|
@@ -60,7 +60,7 @@ class Task[T](WithBriefing, WithJsonExample, WithDependency):
|
|
60
60
|
dependencies: List[str] = Field(default_factory=list)
|
61
61
|
"""A list of file paths, These file are needed to read or write to meet a specific requirement of this task, if it is not directly given out, it SHALL just be a empty list meaning `NOT ASSIGNED`"""
|
62
62
|
|
63
|
-
_output: Queue = PrivateAttr(default_factory=
|
63
|
+
_output: Queue[T | None] = PrivateAttr(default_factory=Queue)
|
64
64
|
"""The output queue of the task."""
|
65
65
|
|
66
66
|
_status: TaskStatus = PrivateAttr(default=TaskStatus.Pending)
|
@@ -131,7 +131,7 @@ class Task[T](WithBriefing, WithJsonExample, WithDependency):
|
|
131
131
|
self.description = description
|
132
132
|
return self
|
133
133
|
|
134
|
-
async def get_output(self) -> T:
|
134
|
+
async def get_output(self) -> T | None:
|
135
135
|
"""Get the output of the task.
|
136
136
|
|
137
137
|
Returns:
|
@@ -232,6 +232,7 @@ class Task[T](WithBriefing, WithJsonExample, WithDependency):
|
|
232
232
|
"""
|
233
233
|
logger.info(f"Cancelling task `{self.name}`")
|
234
234
|
self._status = TaskStatus.Cancelled
|
235
|
+
await self._output.put(None)
|
235
236
|
await env.emit_async(self.cancelled_label, self)
|
236
237
|
return self
|
237
238
|
|
@@ -243,27 +244,38 @@ class Task[T](WithBriefing, WithJsonExample, WithDependency):
|
|
243
244
|
"""
|
244
245
|
logger.info(f"Failing task `{self.name}`")
|
245
246
|
self._status = TaskStatus.Failed
|
247
|
+
await self._output.put(None)
|
246
248
|
await env.emit_async(self.failed_label, self)
|
247
249
|
return self
|
248
250
|
|
249
|
-
|
251
|
+
def publish(self, new_namespace: Optional[EventLike] = None) -> Self:
|
250
252
|
"""Publish the task to the event bus.
|
251
253
|
|
254
|
+
Args:
|
255
|
+
new_namespace(EventLike, optional): The new namespace to move the task to.
|
256
|
+
|
252
257
|
Returns:
|
253
|
-
Task: The published instance of the `Task` class
|
258
|
+
Task: The published instance of the `Task` class.
|
254
259
|
"""
|
260
|
+
if new_namespace:
|
261
|
+
self.move_to(new_namespace)
|
255
262
|
logger.info(f"Publishing task `{(label := self.pending_label)}`")
|
256
|
-
|
263
|
+
env.emit_future(label, self)
|
257
264
|
return self
|
258
265
|
|
259
|
-
async def delegate(self) -> T:
|
260
|
-
"""Delegate the task to the event
|
266
|
+
async def delegate(self, new_namespace: Optional[EventLike] = None) -> T | None:
|
267
|
+
"""Delegate the task to the event.
|
268
|
+
|
269
|
+
Args:
|
270
|
+
new_namespace(EventLike, optional): The new namespace to move the task to.
|
261
271
|
|
262
272
|
Returns:
|
263
|
-
T: The output of the task
|
273
|
+
T|None: The output of the task.
|
264
274
|
"""
|
275
|
+
if new_namespace:
|
276
|
+
self.move_to(new_namespace)
|
265
277
|
logger.info(f"Delegating task `{(label := self.pending_label)}`")
|
266
|
-
|
278
|
+
env.emit_future(label, self)
|
267
279
|
return await self.get_output()
|
268
280
|
|
269
281
|
@property
|
@@ -277,3 +289,43 @@ class Task[T](WithBriefing, WithJsonExample, WithDependency):
|
|
277
289
|
configs.templates.task_briefing_template,
|
278
290
|
self.model_dump(),
|
279
291
|
)
|
292
|
+
|
293
|
+
def is_running(self) -> bool:
|
294
|
+
"""Check if the task is running.
|
295
|
+
|
296
|
+
Returns:
|
297
|
+
bool: True if the task is running, False otherwise.
|
298
|
+
"""
|
299
|
+
return self._status == TaskStatus.Running
|
300
|
+
|
301
|
+
def is_finished(self) -> bool:
|
302
|
+
"""Check if the task is finished.
|
303
|
+
|
304
|
+
Returns:
|
305
|
+
bool: True if the task is finished, False otherwise.
|
306
|
+
"""
|
307
|
+
return self._status == TaskStatus.Finished
|
308
|
+
|
309
|
+
def is_failed(self) -> bool:
|
310
|
+
"""Check if the task is failed.
|
311
|
+
|
312
|
+
Returns:
|
313
|
+
bool: True if the task is failed, False otherwise.
|
314
|
+
"""
|
315
|
+
return self._status == TaskStatus.Failed
|
316
|
+
|
317
|
+
def is_cancelled(self) -> bool:
|
318
|
+
"""Check if the task is cancelled.
|
319
|
+
|
320
|
+
Returns:
|
321
|
+
bool: True if the task is cancelled, False otherwise.
|
322
|
+
"""
|
323
|
+
return self._status == TaskStatus.Cancelled
|
324
|
+
|
325
|
+
def is_pending(self) -> bool:
|
326
|
+
"""Check if the task is pending.
|
327
|
+
|
328
|
+
Returns:
|
329
|
+
bool: True if the task is pending, False otherwise.
|
330
|
+
"""
|
331
|
+
return self._status == TaskStatus.Pending
|
@@ -10,14 +10,15 @@ from fabricatio._rust_instances import template_manager
|
|
10
10
|
from fabricatio.config import configs
|
11
11
|
from fabricatio.journal import logger
|
12
12
|
from fabricatio.models.generic import Base, WithBriefing
|
13
|
-
from fabricatio.models.kwargs_types import ChooseKwargs, GenerateKwargs, LLMKwargs
|
13
|
+
from fabricatio.models.kwargs_types import ChooseKwargs, EmbeddingKwargs, GenerateKwargs, LLMKwargs
|
14
14
|
from fabricatio.models.task import Task
|
15
15
|
from fabricatio.models.tool import Tool, ToolBox
|
16
|
-
from fabricatio.models.utils import Messages
|
16
|
+
from fabricatio.models.utils import Messages, MilvusData
|
17
17
|
from fabricatio.parser import JsonCapture
|
18
18
|
from litellm import stream_chunk_builder
|
19
19
|
from litellm.types.utils import (
|
20
20
|
Choices,
|
21
|
+
EmbeddingResponse,
|
21
22
|
ModelResponse,
|
22
23
|
StreamingChoices,
|
23
24
|
)
|
@@ -61,6 +62,97 @@ class LLMUsage(Base):
|
|
61
62
|
llm_max_tokens: Optional[PositiveInt] = None
|
62
63
|
"""The maximum number of tokens to generate."""
|
63
64
|
|
65
|
+
async def aembedding(
|
66
|
+
self,
|
67
|
+
input_text: List[str],
|
68
|
+
model: Optional[str] = None,
|
69
|
+
dimensions: Optional[int] = None,
|
70
|
+
timeout: Optional[PositiveInt] = None,
|
71
|
+
caching: Optional[bool] = False,
|
72
|
+
) -> EmbeddingResponse:
|
73
|
+
"""Asynchronously generates embeddings for the given input text.
|
74
|
+
|
75
|
+
Args:
|
76
|
+
input_text (List[str]): A list of strings to generate embeddings for.
|
77
|
+
model (Optional[str]): The model to use for embedding. Defaults to the instance's `llm_model` or the global configuration.
|
78
|
+
dimensions (Optional[int]): The dimensions of the embedding. Defaults to None.
|
79
|
+
timeout (Optional[PositiveInt]): The timeout for the embedding request. Defaults to the instance's `llm_timeout` or the global configuration.
|
80
|
+
caching (Optional[bool]): Whether to cache the embedding result. Defaults to False.
|
81
|
+
|
82
|
+
|
83
|
+
Returns:
|
84
|
+
EmbeddingResponse: The response containing the embeddings.
|
85
|
+
"""
|
86
|
+
return await litellm.aembedding(
|
87
|
+
input=input_text,
|
88
|
+
caching=caching,
|
89
|
+
dimensions=dimensions,
|
90
|
+
model=model or self.llm_model or configs.llm.model,
|
91
|
+
timeout=timeout or self.llm_timeout or configs.llm.timeout,
|
92
|
+
api_key=self.llm_api_key.get_secret_value() if self.llm_api_key else configs.llm.api_key.get_secret_value(),
|
93
|
+
api_base=self.llm_api_endpoint.unicode_string().rstrip(
|
94
|
+
"/"
|
95
|
+
) # seems embedding function takes no base_url end with a slash
|
96
|
+
if self.llm_api_endpoint
|
97
|
+
else configs.llm.api_endpoint.unicode_string().rstrip("/"),
|
98
|
+
)
|
99
|
+
|
100
|
+
@overload
|
101
|
+
async def vectorize(self, input_text: List[str], **kwargs: Unpack[EmbeddingKwargs]) -> List[List[float]]: ...
|
102
|
+
@overload
|
103
|
+
async def vectorize(self, input_text: str, **kwargs: Unpack[EmbeddingKwargs]) -> List[float]: ...
|
104
|
+
|
105
|
+
async def vectorize(
|
106
|
+
self, input_text: List[str] | str, **kwargs: Unpack[EmbeddingKwargs]
|
107
|
+
) -> List[List[float]] | List[float]:
|
108
|
+
"""Asynchronously generates vector embeddings for the given input text.
|
109
|
+
|
110
|
+
Args:
|
111
|
+
input_text (List[str] | str): A string or list of strings to generate embeddings for.
|
112
|
+
**kwargs (Unpack[EmbeddingKwargs]): Additional keyword arguments for embedding.
|
113
|
+
|
114
|
+
Returns:
|
115
|
+
List[List[float]] | List[float]: The generated embeddings.
|
116
|
+
"""
|
117
|
+
if isinstance(input_text, str):
|
118
|
+
return (await self.aembedding([input_text], **kwargs)).data[0].get("embedding")
|
119
|
+
|
120
|
+
return [o.get("embedding") for o in (await self.aembedding(input_text, **kwargs)).data]
|
121
|
+
|
122
|
+
@overload
|
123
|
+
async def pack(
|
124
|
+
self, input_text: List[str], subject: Optional[str] = None, **kwargs: Unpack[EmbeddingKwargs]
|
125
|
+
) -> List[MilvusData]: ...
|
126
|
+
@overload
|
127
|
+
async def pack(
|
128
|
+
self, input_text: str, subject: Optional[str] = None, **kwargs: Unpack[EmbeddingKwargs]
|
129
|
+
) -> MilvusData: ...
|
130
|
+
|
131
|
+
async def pack(
|
132
|
+
self, input_text: List[str] | str, subject: Optional[str] = None, **kwargs: Unpack[EmbeddingKwargs]
|
133
|
+
) -> List[MilvusData] | MilvusData:
|
134
|
+
"""Asynchronously generates MilvusData objects for the given input text.
|
135
|
+
|
136
|
+
Args:
|
137
|
+
input_text (List[str] | str): A string or list of strings to generate embeddings for.
|
138
|
+
subject (Optional[str]): The subject of the input text. Defaults to None.
|
139
|
+
**kwargs (Unpack[EmbeddingKwargs]): Additional keyword arguments for embedding.
|
140
|
+
|
141
|
+
Returns:
|
142
|
+
List[MilvusData] | MilvusData: The generated MilvusData objects.
|
143
|
+
"""
|
144
|
+
if isinstance(input_text, str):
|
145
|
+
return MilvusData(vector=await self.vectorize(input_text, **kwargs), text=input_text, subject=subject)
|
146
|
+
vecs = await self.vectorize(input_text, **kwargs)
|
147
|
+
return [
|
148
|
+
MilvusData(
|
149
|
+
vector=vec,
|
150
|
+
text=text,
|
151
|
+
subject=subject,
|
152
|
+
)
|
153
|
+
for text, vec in zip(input_text, vecs, strict=True)
|
154
|
+
]
|
155
|
+
|
64
156
|
async def aquery(
|
65
157
|
self,
|
66
158
|
messages: List[Dict[str, str]],
|
@@ -1,6 +1,6 @@
|
|
1
1
|
"""A module containing utility classes for the models."""
|
2
2
|
|
3
|
-
from typing import Dict, List, Literal, Self
|
3
|
+
from typing import Any, Dict, List, Literal, Optional, Self
|
4
4
|
|
5
5
|
from pydantic import BaseModel, ConfigDict, Field
|
6
6
|
|
@@ -76,3 +76,52 @@ class Messages(list):
|
|
76
76
|
list[dict]: A list of dictionaries representing the messages.
|
77
77
|
"""
|
78
78
|
return [message.model_dump() for message in self]
|
79
|
+
|
80
|
+
|
81
|
+
class MilvusData(BaseModel):
|
82
|
+
"""A class representing data stored in Milvus."""
|
83
|
+
|
84
|
+
model_config = ConfigDict(use_attribute_docstrings=True)
|
85
|
+
id: Optional[int] = Field(default=None)
|
86
|
+
"""The identifier of the data."""
|
87
|
+
|
88
|
+
vector: List[float]
|
89
|
+
"""The vector representation of the data."""
|
90
|
+
|
91
|
+
text: str
|
92
|
+
"""The text representation of the data."""
|
93
|
+
|
94
|
+
subject: Optional[str] = Field(default=None)
|
95
|
+
"""A subject label that we use to demo metadata filtering later."""
|
96
|
+
|
97
|
+
def prepare_insertion(self) -> Dict[str, Any]:
|
98
|
+
"""Prepares the data for insertion into Milvus.
|
99
|
+
|
100
|
+
Returns:
|
101
|
+
dict: A dictionary containing the data to be inserted into Milvus.
|
102
|
+
"""
|
103
|
+
return self.model_dump(exclude_none=True)
|
104
|
+
|
105
|
+
def update_subject(self, new_subject: str) -> Self:
|
106
|
+
"""Updates the subject label of the data.
|
107
|
+
|
108
|
+
Args:
|
109
|
+
new_subject (str): The new subject label.
|
110
|
+
|
111
|
+
Returns:
|
112
|
+
Self: The updated instance of MilvusData.
|
113
|
+
"""
|
114
|
+
self.subject = new_subject
|
115
|
+
return self
|
116
|
+
|
117
|
+
def update_id(self, new_id: int) -> Self:
|
118
|
+
"""Updates the identifier of the data.
|
119
|
+
|
120
|
+
Args:
|
121
|
+
new_id (int): The new identifier.
|
122
|
+
|
123
|
+
Returns:
|
124
|
+
Self: The updated instance of MilvusData.
|
125
|
+
"""
|
126
|
+
self.id = new_id
|
127
|
+
return self
|
Binary file
|