fabricatio 0.2.0.dev11__cp312-cp312-manylinux_2_34_x86_64.whl → 0.2.0.dev13__cp312-cp312-manylinux_2_34_x86_64.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 +1 -1
- fabricatio/_rust.cpython-312-x86_64-linux-gnu.so +0 -0
- fabricatio/decorators.py +4 -25
- fabricatio/models/action.py +1 -2
- fabricatio/models/generic.py +169 -27
- fabricatio/models/task.py +3 -6
- fabricatio/models/tool.py +52 -7
- fabricatio/parser.py +26 -7
- fabricatio/toolboxes/arithmetic.py +62 -0
- fabricatio-0.2.0.dev13.data/scripts/tdown +0 -0
- {fabricatio-0.2.0.dev11.dist-info → fabricatio-0.2.0.dev13.dist-info}/METADATA +4 -1
- {fabricatio-0.2.0.dev11.dist-info → fabricatio-0.2.0.dev13.dist-info}/RECORD +14 -13
- fabricatio-0.2.0.dev11.data/scripts/tdown +0 -0
- {fabricatio-0.2.0.dev11.dist-info → fabricatio-0.2.0.dev13.dist-info}/WHEEL +0 -0
- {fabricatio-0.2.0.dev11.dist-info → fabricatio-0.2.0.dev13.dist-info}/licenses/LICENSE +0 -0
fabricatio/__init__.py
CHANGED
Binary file
|
fabricatio/decorators.py
CHANGED
@@ -19,30 +19,9 @@ def depend_on_external_cmd[**P, R](bin_name: str, install_tip: str) -> Callable[
|
|
19
19
|
RuntimeError: If the required binary is not found.
|
20
20
|
"""
|
21
21
|
|
22
|
-
def
|
23
|
-
"""Decorator to wrap the function with binary presence check.
|
24
|
-
|
25
|
-
Args:
|
26
|
-
func (Callable[P, R]): The function to be decorated.
|
27
|
-
|
28
|
-
Returns:
|
29
|
-
Callable[P, R]: The wrapped function.
|
30
|
-
"""
|
31
|
-
|
22
|
+
def _decorator(func: Callable[P, R]) -> Callable[P, R]:
|
32
23
|
@wraps(func)
|
33
|
-
def
|
34
|
-
"""Wrapper function to check for the presence of the required binary.
|
35
|
-
|
36
|
-
Args:
|
37
|
-
*args: Positional arguments for the function.
|
38
|
-
**kwargs: Keyword arguments for the function.
|
39
|
-
|
40
|
-
Returns:
|
41
|
-
R: The result of the function call.
|
42
|
-
|
43
|
-
Raises:
|
44
|
-
RuntimeError: If the required binary is not found.
|
45
|
-
"""
|
24
|
+
def _wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
46
25
|
if which(bin_name) is None:
|
47
26
|
err = (
|
48
27
|
f"{bin_name} is required to run function: {func.__name__}, please install it first.\n{install_tip}"
|
@@ -51,6 +30,6 @@ def depend_on_external_cmd[**P, R](bin_name: str, install_tip: str) -> Callable[
|
|
51
30
|
raise RuntimeError(err)
|
52
31
|
return func(*args, **kwargs)
|
53
32
|
|
54
|
-
return
|
33
|
+
return _wrapper
|
55
34
|
|
56
|
-
return
|
35
|
+
return _decorator
|
fabricatio/models/action.py
CHANGED
@@ -123,6 +123,5 @@ class WorkFlow[A: Type[Action] | Action](WithBriefing, LLMUsage):
|
|
123
123
|
|
124
124
|
def fallback_to_self(self) -> Self:
|
125
125
|
"""Set the fallback for each step to the workflow itself."""
|
126
|
-
|
127
|
-
step.fallback_to(self)
|
126
|
+
self.hold_to(self._instances)
|
128
127
|
return self
|
fabricatio/models/generic.py
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
"""This module defines generic classes for models in the Fabricatio library."""
|
2
2
|
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import Callable, Dict, List, Optional, Self
|
4
|
+
from typing import Callable, Dict, Iterable, List, Optional, Self, Union
|
5
5
|
|
6
6
|
import litellm
|
7
7
|
import orjson
|
8
|
+
from fabricatio._rust_instances import template_manager
|
8
9
|
from fabricatio.config import configs
|
9
10
|
from fabricatio.fs.readers import magika
|
10
11
|
from fabricatio.models.utils import Messages
|
12
|
+
from fabricatio.parser import JsonCapture
|
11
13
|
from litellm.types.utils import Choices, ModelResponse, StreamingChoices
|
12
14
|
from pydantic import (
|
13
15
|
BaseModel,
|
@@ -15,6 +17,7 @@ from pydantic import (
|
|
15
17
|
Field,
|
16
18
|
HttpUrl,
|
17
19
|
NonNegativeFloat,
|
20
|
+
NonNegativeInt,
|
18
21
|
PositiveInt,
|
19
22
|
SecretStr,
|
20
23
|
)
|
@@ -274,21 +277,159 @@ class LLMUsage(Base):
|
|
274
277
|
for _ in range(max_validations):
|
275
278
|
if (
|
276
279
|
response := await self.aask(
|
277
|
-
question,
|
278
|
-
system_message,
|
279
|
-
model,
|
280
|
-
temperature,
|
281
|
-
stop,
|
282
|
-
top_p,
|
283
|
-
max_tokens,
|
284
|
-
stream,
|
285
|
-
timeout,
|
286
|
-
max_retries,
|
280
|
+
question=question,
|
281
|
+
system_message=system_message,
|
282
|
+
model=model,
|
283
|
+
temperature=temperature,
|
284
|
+
stop=stop,
|
285
|
+
top_p=top_p,
|
286
|
+
max_tokens=max_tokens,
|
287
|
+
stream=stream,
|
288
|
+
timeout=timeout,
|
289
|
+
max_retries=max_retries,
|
287
290
|
)
|
288
291
|
) and (validated := validator(response)):
|
289
292
|
return validated
|
290
293
|
raise ValueError("Failed to validate the response.")
|
291
294
|
|
295
|
+
async def achoose[T: WithBriefing](
|
296
|
+
self,
|
297
|
+
instruction: str,
|
298
|
+
choices: List[T],
|
299
|
+
k: NonNegativeInt = 0,
|
300
|
+
max_validations: PositiveInt = 2,
|
301
|
+
system_message: str = "",
|
302
|
+
model: str | None = None,
|
303
|
+
temperature: NonNegativeFloat | None = None,
|
304
|
+
stop: str | List[str] | None = None,
|
305
|
+
top_p: NonNegativeFloat | None = None,
|
306
|
+
max_tokens: PositiveInt | None = None,
|
307
|
+
stream: bool | None = None,
|
308
|
+
timeout: PositiveInt | None = None,
|
309
|
+
max_retries: PositiveInt | None = None,
|
310
|
+
) -> List[T]:
|
311
|
+
"""Asynchronously executes a multi-choice decision-making process, generating a prompt based on the instruction and options, and validates the returned selection results.
|
312
|
+
|
313
|
+
Args:
|
314
|
+
instruction: The user-provided instruction/question description.
|
315
|
+
choices: A list of candidate options, requiring elements to have `name` and `briefing` fields.
|
316
|
+
k: The number of choices to select, 0 means infinite.
|
317
|
+
max_validations: Maximum number of validation failures, default is 2.
|
318
|
+
system_message: Custom system-level prompt, defaults to an empty string.
|
319
|
+
model: The name of the LLM model to use.
|
320
|
+
temperature: Sampling temperature to control randomness in generation.
|
321
|
+
stop: Stop condition string or list for generation.
|
322
|
+
top_p: Core sampling probability threshold.
|
323
|
+
max_tokens: Maximum token limit for the generated result.
|
324
|
+
stream: Whether to enable streaming response mode.
|
325
|
+
timeout: Request timeout in seconds.
|
326
|
+
max_retries: Maximum number of retries.
|
327
|
+
|
328
|
+
Returns:
|
329
|
+
List[T]: The final validated selection result list, with element types matching the input `choices`.
|
330
|
+
|
331
|
+
Important:
|
332
|
+
- Uses a template engine to generate structured prompts.
|
333
|
+
- Ensures response compliance through JSON parsing and format validation.
|
334
|
+
- Relies on `aask_validate` to implement retry mechanisms with validation.
|
335
|
+
"""
|
336
|
+
prompt = template_manager.render_template(
|
337
|
+
"make_choice",
|
338
|
+
{
|
339
|
+
"instruction": instruction,
|
340
|
+
"options": [m.model_dump(include={"name", "briefing"}) for m in choices],
|
341
|
+
"k": k,
|
342
|
+
},
|
343
|
+
)
|
344
|
+
names = [c.name for c in choices]
|
345
|
+
|
346
|
+
def _validate(response: str) -> List[T] | None:
|
347
|
+
ret = JsonCapture.convert_with(response, orjson.loads)
|
348
|
+
if not isinstance(ret, List) or len(ret) != k:
|
349
|
+
return None
|
350
|
+
if any(n not in names for n in ret):
|
351
|
+
return None
|
352
|
+
return ret
|
353
|
+
|
354
|
+
return await self.aask_validate(
|
355
|
+
question=prompt,
|
356
|
+
validator=_validate,
|
357
|
+
max_validations=max_validations,
|
358
|
+
system_message=system_message,
|
359
|
+
model=model,
|
360
|
+
temperature=temperature,
|
361
|
+
stop=stop,
|
362
|
+
top_p=top_p,
|
363
|
+
max_tokens=max_tokens,
|
364
|
+
stream=stream,
|
365
|
+
timeout=timeout,
|
366
|
+
max_retries=max_retries,
|
367
|
+
)
|
368
|
+
|
369
|
+
async def ajudge(
|
370
|
+
self,
|
371
|
+
prompt: str,
|
372
|
+
affirm_case: str = "",
|
373
|
+
deny_case: str = "",
|
374
|
+
max_validations: PositiveInt = 2,
|
375
|
+
system_message: str = "",
|
376
|
+
model: str | None = None,
|
377
|
+
temperature: NonNegativeFloat | None = None,
|
378
|
+
stop: str | List[str] | None = None,
|
379
|
+
top_p: NonNegativeFloat | None = None,
|
380
|
+
max_tokens: PositiveInt | None = None,
|
381
|
+
stream: bool | None = None,
|
382
|
+
timeout: PositiveInt | None = None,
|
383
|
+
max_retries: PositiveInt | None = None,
|
384
|
+
) -> bool:
|
385
|
+
"""Asynchronously judges a prompt using AI validation.
|
386
|
+
|
387
|
+
Args:
|
388
|
+
prompt (str): The input prompt to be judged.
|
389
|
+
affirm_case (str, optional): The affirmative case for the AI model. Defaults to "".
|
390
|
+
deny_case (str, optional): The negative case for the AI model. Defaults to "".
|
391
|
+
max_validations (PositiveInt, optional): Maximum number of validation attempts. Defaults to 2.
|
392
|
+
system_message (str, optional): System message for the AI model. Defaults to "".
|
393
|
+
model (str | None, optional): AI model to use. Defaults to None.
|
394
|
+
temperature (NonNegativeFloat | None, optional): Sampling temperature. Defaults to None.
|
395
|
+
stop (str | List[str] | None, optional): Stop sequences. Defaults to None.
|
396
|
+
top_p (NonNegativeFloat | None, optional): Nucleus sampling parameter. Defaults to None.
|
397
|
+
max_tokens (PositiveInt | None, optional): Maximum number of tokens to generate. Defaults to None.
|
398
|
+
stream (bool | None, optional): Whether to stream the response. Defaults to None.
|
399
|
+
timeout (PositiveInt | None, optional): Timeout in seconds. Defaults to None.
|
400
|
+
max_retries (PositiveInt | None, optional): Maximum number of retries. Defaults to None.
|
401
|
+
|
402
|
+
Returns:
|
403
|
+
bool: The judgment result (True or False) based on the AI's response.
|
404
|
+
|
405
|
+
Notes:
|
406
|
+
The method uses an internal validator to ensure the response is a boolean value.
|
407
|
+
If the response cannot be converted to a boolean, it will return None.
|
408
|
+
"""
|
409
|
+
|
410
|
+
def _validate(response: str) -> bool | None:
|
411
|
+
ret = JsonCapture.convert_with(response, orjson.loads)
|
412
|
+
if not isinstance(ret, bool):
|
413
|
+
return None
|
414
|
+
return ret
|
415
|
+
|
416
|
+
return await self.aask_validate(
|
417
|
+
question=template_manager.render_template(
|
418
|
+
"make_judgment", {"prompt": prompt, "affirm_case": affirm_case, "deny_case": deny_case}
|
419
|
+
),
|
420
|
+
validator=_validate,
|
421
|
+
max_validations=max_validations,
|
422
|
+
system_message=system_message,
|
423
|
+
model=model,
|
424
|
+
temperature=temperature,
|
425
|
+
stop=stop,
|
426
|
+
top_p=top_p,
|
427
|
+
max_tokens=max_tokens,
|
428
|
+
stream=stream,
|
429
|
+
timeout=timeout,
|
430
|
+
max_retries=max_retries,
|
431
|
+
)
|
432
|
+
|
292
433
|
def fallback_to(self, other: "LLMUsage") -> Self:
|
293
434
|
"""Fallback to another instance's attribute values if the current instance's attributes are None.
|
294
435
|
|
@@ -298,23 +439,9 @@ class LLMUsage(Base):
|
|
298
439
|
Returns:
|
299
440
|
Self: The current instance, allowing for method chaining.
|
300
441
|
"""
|
301
|
-
# Define the list of attribute names to check and potentially copy
|
302
|
-
attr_names = [
|
303
|
-
"llm_api_endpoint",
|
304
|
-
"llm_api_key",
|
305
|
-
"llm_model",
|
306
|
-
"llm_stop_sign",
|
307
|
-
"llm_temperature",
|
308
|
-
"llm_top_p",
|
309
|
-
"llm_generation_count",
|
310
|
-
"llm_stream",
|
311
|
-
"llm_max_tokens",
|
312
|
-
"llm_timeout",
|
313
|
-
"llm_max_retries",
|
314
|
-
]
|
315
|
-
|
316
442
|
# Iterate over the attribute names and copy values from 'other' to 'self' where applicable
|
317
|
-
|
443
|
+
# noinspection PydanticTypeChecker,PyTypeChecker
|
444
|
+
for attr_name in LLMUsage.model_fields:
|
318
445
|
# Copy the attribute value from 'other' to 'self' only if 'self' has None and 'other' has a non-None value
|
319
446
|
if getattr(self, attr_name) is None and (attr := getattr(other, attr_name)) is not None:
|
320
447
|
setattr(self, attr_name, attr)
|
@@ -322,6 +449,21 @@ class LLMUsage(Base):
|
|
322
449
|
# Return the current instance to allow for method chaining
|
323
450
|
return self
|
324
451
|
|
452
|
+
def hold_to(self, others: Union["LLMUsage", Iterable["LLMUsage"]]) -> Self:
|
453
|
+
"""Hold to another instance's attribute values if the current instance's attributes are None.
|
454
|
+
|
455
|
+
Args:
|
456
|
+
others (LLMUsage | Iterable[LLMUsage]): Another instance or iterable of instances from which to copy attribute values.
|
457
|
+
|
458
|
+
Returns:
|
459
|
+
Self: The current instance, allowing for method chaining.
|
460
|
+
"""
|
461
|
+
for other in others:
|
462
|
+
# noinspection PyTypeChecker,PydanticTypeChecker
|
463
|
+
for attr_name in LLMUsage.model_fields:
|
464
|
+
if (attr := getattr(self, attr_name)) is not None and getattr(other, attr_name) is None:
|
465
|
+
setattr(other, attr_name, attr)
|
466
|
+
|
325
467
|
|
326
468
|
class WithJsonExample(Base):
|
327
469
|
"""Class that provides a JSON schema for the model."""
|
fabricatio/models/task.py
CHANGED
@@ -268,16 +268,13 @@ class ProposeTask(LLMUsage, WithBriefing):
|
|
268
268
|
try:
|
269
269
|
cap = JsonCapture.capture(response)
|
270
270
|
logger.debug(f"Response: \n{response}")
|
271
|
-
logger.info(f"Captured JSON: \n{cap
|
272
|
-
return Task.model_validate_json(cap
|
271
|
+
logger.info(f"Captured JSON: \n{cap}")
|
272
|
+
return Task.model_validate_json(cap)
|
273
273
|
except ValidationError as e:
|
274
274
|
logger.error(f"Failed to parse task from JSON: {e}")
|
275
275
|
return None
|
276
276
|
|
277
|
-
template_data = {
|
278
|
-
"prompt": prompt,
|
279
|
-
"json_example": Task.json_example()
|
280
|
-
}
|
277
|
+
template_data = {"prompt": prompt, "json_example": Task.json_example()}
|
281
278
|
return await self.aask_validate(
|
282
279
|
template_manager.render_template("propose_task", template_data),
|
283
280
|
_validate_json,
|
fabricatio/models/tool.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
"""A module for defining tools and toolboxes."""
|
2
2
|
|
3
|
-
from inspect import
|
4
|
-
from typing import Any, Callable, List, Self
|
3
|
+
from inspect import iscoroutinefunction, signature
|
4
|
+
from typing import Any, Callable, Iterable, List, Optional, Self, Union
|
5
5
|
|
6
|
-
from fabricatio.models.generic import WithBriefing
|
6
|
+
from fabricatio.models.generic import Base, WithBriefing
|
7
7
|
from pydantic import Field
|
8
8
|
|
9
9
|
|
@@ -24,6 +24,7 @@ class Tool[**P, R](WithBriefing):
|
|
24
24
|
self.name = self.name or self.source.__name__
|
25
25
|
assert self.name, "The tool must have a name."
|
26
26
|
self.description = self.description or self.source.__doc__ or ""
|
27
|
+
self.description = self.description.strip()
|
27
28
|
|
28
29
|
def invoke(self, *args: P.args, **kwargs: P.kwargs) -> R:
|
29
30
|
"""Invoke the tool's source function with the provided arguments."""
|
@@ -36,10 +37,15 @@ class Tool[**P, R](WithBriefing):
|
|
36
37
|
Returns:
|
37
38
|
str: A brief description of the tool.
|
38
39
|
"""
|
39
|
-
source_signature = str(signature(self.source))
|
40
40
|
# 获取源函数的返回类型
|
41
|
-
|
42
|
-
return f"{self.
|
41
|
+
|
42
|
+
return f"{'async ' if iscoroutinefunction(self.source) else ''}def {self.name}{signature(self.source)}\n{_desc_wrapper(self.description)}"
|
43
|
+
|
44
|
+
|
45
|
+
def _desc_wrapper(desc: str) -> str:
|
46
|
+
lines = desc.split("\n")
|
47
|
+
lines_indent = [f" {line}" for line in ['"""', *lines, '"""']]
|
48
|
+
return "\n".join(lines_indent)
|
43
49
|
|
44
50
|
|
45
51
|
class ToolBox(WithBriefing):
|
@@ -79,7 +85,7 @@ class ToolBox(WithBriefing):
|
|
79
85
|
Returns:
|
80
86
|
str: A brief description of the toolbox.
|
81
87
|
"""
|
82
|
-
list_out = "\n\n".join([f"
|
88
|
+
list_out = "\n\n".join([f"{tool.briefing}" for tool in self.tools])
|
83
89
|
toc = f"## {self.name}: {self.description}\n## {len(self.tools)} tools available:"
|
84
90
|
return f"{toc}\n\n{list_out}"
|
85
91
|
|
@@ -98,3 +104,42 @@ class ToolBox(WithBriefing):
|
|
98
104
|
tool = next((tool for tool in self.tools if tool.name == name), None)
|
99
105
|
assert tool, f"No tool named {name} found."
|
100
106
|
return tool
|
107
|
+
|
108
|
+
|
109
|
+
class ToolUsage(Base):
|
110
|
+
"""A class representing the usage of tools in a task."""
|
111
|
+
|
112
|
+
toolboxes: Optional[List[ToolBox]]
|
113
|
+
"""The tools used by the task, a list of ToolBox instances."""
|
114
|
+
|
115
|
+
def supply_tools_from(self, others: Union["ToolUsage", Iterable["ToolUsage"]]) -> Self:
|
116
|
+
"""Supplies tools from other ToolUsage instances to this instance.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
others ("ToolUsage" | Iterable["ToolUsage"]): A single ToolUsage instance or an iterable of ToolUsage instances
|
120
|
+
from which to take tools.
|
121
|
+
|
122
|
+
Returns:
|
123
|
+
Self: The current ToolUsage instance with updated tools.
|
124
|
+
"""
|
125
|
+
if isinstance(others, ToolUsage):
|
126
|
+
others = [others]
|
127
|
+
for other in others:
|
128
|
+
self.toolboxes.extend(other.toolboxes)
|
129
|
+
return self
|
130
|
+
|
131
|
+
def provide_tools_to(self, others: Union["ToolUsage", Iterable["ToolUsage"]]) -> Self:
|
132
|
+
"""Provides tools from this instance to other ToolUsage instances.
|
133
|
+
|
134
|
+
Args:
|
135
|
+
others ("ToolUsage" | Iterable["ToolUsage"]): A single ToolUsage instance or an iterable of ToolUsage instances
|
136
|
+
to which to provide tools.
|
137
|
+
|
138
|
+
Returns:
|
139
|
+
Self: The current ToolUsage instance.
|
140
|
+
"""
|
141
|
+
if isinstance(others, ToolUsage):
|
142
|
+
others = [others]
|
143
|
+
for other in others:
|
144
|
+
other.toolboxes.extend(self.toolboxes)
|
145
|
+
return self
|
fabricatio/parser.py
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
"""A module to parse text using regular expressions."""
|
2
2
|
|
3
|
-
from typing import Any, Self, Tuple
|
3
|
+
from typing import Any, Callable, Self, Tuple
|
4
4
|
|
5
5
|
import regex
|
6
|
-
from pydantic import Field, PositiveInt, PrivateAttr
|
6
|
+
from pydantic import BaseModel, ConfigDict, Field, PositiveInt, PrivateAttr
|
7
7
|
from regex import Pattern, compile
|
8
8
|
|
9
|
-
from fabricatio.
|
9
|
+
from fabricatio.journal import logger
|
10
10
|
|
11
11
|
|
12
|
-
class Capture(
|
12
|
+
class Capture(BaseModel):
|
13
13
|
"""A class to capture patterns in text using regular expressions.
|
14
14
|
|
15
15
|
Attributes:
|
@@ -17,6 +17,7 @@ class Capture(Base):
|
|
17
17
|
_compiled (Pattern): The compiled regular expression pattern.
|
18
18
|
"""
|
19
19
|
|
20
|
+
model_config = ConfigDict(use_attribute_docstrings=True)
|
20
21
|
target_groups: Tuple[int, ...] = Field(default_factory=tuple)
|
21
22
|
"""The target groups to capture from the pattern."""
|
22
23
|
pattern: str = Field(frozen=True)
|
@@ -33,7 +34,7 @@ class Capture(Base):
|
|
33
34
|
"""
|
34
35
|
self._compiled = compile(self.pattern, self.flags)
|
35
36
|
|
36
|
-
def capture(self, text: str) -> Tuple[str, ...] | None:
|
37
|
+
def capture(self, text: str) -> Tuple[str, ...] | str | None:
|
37
38
|
"""Capture the first occurrence of the pattern in the given text.
|
38
39
|
|
39
40
|
Args:
|
@@ -49,7 +50,25 @@ class Capture(Base):
|
|
49
50
|
|
50
51
|
if self.target_groups:
|
51
52
|
return tuple(match.group(g) for g in self.target_groups)
|
52
|
-
return
|
53
|
+
return match.group(1)
|
54
|
+
|
55
|
+
def convert_with[T](self, text: str, convertor: Callable[[Tuple[str, ...]], T] | Callable[[str], T]) -> T | None:
|
56
|
+
"""Convert the given text using the pattern.
|
57
|
+
|
58
|
+
Args:
|
59
|
+
text (str): The text to search the pattern in.
|
60
|
+
convertor (Callable[[Tuple[str, ...]], T] | Callable[[str], T]): The function to convert the captured text.
|
61
|
+
|
62
|
+
Returns:
|
63
|
+
str | None: The converted text if the pattern is found, otherwise None.
|
64
|
+
"""
|
65
|
+
if cap := self.capture(text) is None:
|
66
|
+
return None
|
67
|
+
try:
|
68
|
+
return convertor(cap)
|
69
|
+
except ValueError as e:
|
70
|
+
logger.error(f"Failed to convert text using convertor: {convertor.__name__}, error: \n{e}")
|
71
|
+
return None
|
53
72
|
|
54
73
|
@classmethod
|
55
74
|
def capture_code_block(cls, language: str) -> Self:
|
@@ -61,7 +80,7 @@ class Capture(Base):
|
|
61
80
|
Returns:
|
62
81
|
Self: The instance of the class with the captured code block.
|
63
82
|
"""
|
64
|
-
return cls(pattern=f"```{language}\n(.*?)\n```"
|
83
|
+
return cls(pattern=f"```{language}\n(.*?)\n```")
|
65
84
|
|
66
85
|
|
67
86
|
JsonCapture = Capture.capture_code_block("json")
|
@@ -0,0 +1,62 @@
|
|
1
|
+
"""Arithmetic tools for Fabricatio."""
|
2
|
+
|
3
|
+
from fabricatio.models.tool import ToolBox
|
4
|
+
|
5
|
+
arithmetic_tools = ToolBox(name="ArithmeticToolBox", description="A toolbox for arithmetic operations.")
|
6
|
+
|
7
|
+
|
8
|
+
@arithmetic_tools.collect_tool
|
9
|
+
def add(a: float, b: float) -> float:
|
10
|
+
"""Add two numbers.
|
11
|
+
|
12
|
+
Args:
|
13
|
+
a (float): The first number.
|
14
|
+
b (float): The second number.
|
15
|
+
|
16
|
+
Returns:
|
17
|
+
float: The sum of the two numbers.
|
18
|
+
"""
|
19
|
+
return a + b
|
20
|
+
|
21
|
+
|
22
|
+
@arithmetic_tools.collect_tool
|
23
|
+
def subtract(a: float, b: float) -> float:
|
24
|
+
"""Subtract two numbers.
|
25
|
+
|
26
|
+
Args:
|
27
|
+
a (float): The first number.
|
28
|
+
b (float): The second number.
|
29
|
+
|
30
|
+
Returns:
|
31
|
+
float: The result of subtracting b from a.
|
32
|
+
"""
|
33
|
+
return a - b
|
34
|
+
|
35
|
+
|
36
|
+
@arithmetic_tools.collect_tool
|
37
|
+
def multiply(a: float, b: float) -> float:
|
38
|
+
"""Multiply two numbers.
|
39
|
+
|
40
|
+
Args:
|
41
|
+
a (float): The first number.
|
42
|
+
b (float): The second number.
|
43
|
+
|
44
|
+
Returns:
|
45
|
+
float: The product of the two numbers.
|
46
|
+
"""
|
47
|
+
return a * b
|
48
|
+
|
49
|
+
|
50
|
+
@arithmetic_tools.collect_tool
|
51
|
+
def divide(a: float, b: float) -> float:
|
52
|
+
"""Divide two numbers.
|
53
|
+
|
54
|
+
Args:
|
55
|
+
a (float): The numerator.
|
56
|
+
b (float): The denominator (must not be zero).
|
57
|
+
|
58
|
+
Returns:
|
59
|
+
float: The result of dividing a by b.
|
60
|
+
|
61
|
+
"""
|
62
|
+
return a / b
|
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fabricatio
|
3
|
-
Version: 0.2.0.
|
3
|
+
Version: 0.2.0.dev13
|
4
4
|
Classifier: License :: OSI Approved :: MIT License
|
5
5
|
Classifier: Programming Language :: Rust
|
6
6
|
Classifier: Programming Language :: Python :: 3.12
|
@@ -28,6 +28,9 @@ Keywords: ai,agents,multi-agent,llm,pyo3
|
|
28
28
|
Author-email: Whth <zettainspector@foxmail.com>
|
29
29
|
Requires-Python: >=3.12
|
30
30
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
31
|
+
Project-URL: Homepage, https://github.com/Whth/fabricatio
|
32
|
+
Project-URL: Repository, https://github.com/Whth/fabricatio
|
33
|
+
Project-URL: Issues, https://github.com/Whth/fabricatio/issues
|
31
34
|
|
32
35
|
# Fabricatio
|
33
36
|
|
@@ -1,20 +1,21 @@
|
|
1
|
-
fabricatio-0.2.0.
|
2
|
-
fabricatio-0.2.0.
|
3
|
-
fabricatio-0.2.0.
|
1
|
+
fabricatio-0.2.0.dev13.dist-info/METADATA,sha256=Q4r0vbpk3dJdnWiK1pnt8aj19fPelsaKZH1XXtAw68E,6005
|
2
|
+
fabricatio-0.2.0.dev13.dist-info/WHEEL,sha256=RIvmwLDYujv60MYBx2jxyP4vdn1DD7X0kBgz1TQvZuc,108
|
3
|
+
fabricatio-0.2.0.dev13.dist-info/licenses/LICENSE,sha256=yDZaTLnOi03bi3Dk6f5IjhLUc5old2yOsihHWU0z-i0,1067
|
4
4
|
fabricatio/fs/__init__.py,sha256=bYE9r8uR0dtknzbg_YaGv_6Wwa27ntkQt0Tl7Kb3HFI,117
|
5
5
|
fabricatio/fs/readers.py,sha256=E219Pef7gknltkHjL9iZXwjI841_EPFpNvDG9KBUG3g,118
|
6
6
|
fabricatio/toolboxes/__init__.py,sha256=8gd8yPhhQBO0A37w1zqVLfbOG-pyCPrveEtO0MX042A,151
|
7
7
|
fabricatio/toolboxes/task.py,sha256=G_nNYT8Sy5ll6YmXES458MUmgJnDSBNwlozyJewdnzY,200
|
8
|
-
fabricatio/
|
8
|
+
fabricatio/toolboxes/arithmetic.py,sha256=bG4ngqBrTaj4zHxpMTbK-JQ4Si96UiiHz7fufSQWu-0,1297
|
9
|
+
fabricatio/__init__.py,sha256=UE2qARwRgL3T1NgnzK9b4Cx3eksUvNZmN_rf-dycM4E,881
|
9
10
|
fabricatio/core.py,sha256=apwXgI94DCWpGujGlsmXsTZQvJOQMB9llmuUo7ohd-4,5771
|
10
11
|
fabricatio/config.py,sha256=Or_PzOzXy_4Rqje1r788sID4bxILXhNC3r7eelcZJy0,7852
|
11
|
-
fabricatio/decorators.py,sha256=
|
12
|
+
fabricatio/decorators.py,sha256=UgW8_pV_RUm0a69co1POnKvJHh9Qy2R0pyh1BtEKzFI,1169
|
12
13
|
fabricatio/journal.py,sha256=u6YTKrD9EoebbR8guvAe5zSqWV1nS-BGyKxZR_Sw2ik,684
|
13
|
-
fabricatio/models/generic.py,sha256=
|
14
|
-
fabricatio/models/action.py,sha256=
|
15
|
-
fabricatio/models/task.py,sha256=
|
14
|
+
fabricatio/models/generic.py,sha256=pV84sWgZZItgotFTchfyixSLSnmv5GkumSv_0frPK38,22402
|
15
|
+
fabricatio/models/action.py,sha256=VL_A8BWOuCYQCjwCAm0vExA88KSwm6VkluXHOtHijUw,4882
|
16
|
+
fabricatio/models/task.py,sha256=2jSttV7Yod2Waz16RByFZrRZT07YThs5Vw5pgbjbD1s,9063
|
16
17
|
fabricatio/models/role.py,sha256=1vhpHRKJ6f7PDBLl6jYRZbxTJyrVhNN3FEEh_HAwU3o,990
|
17
|
-
fabricatio/models/tool.py,sha256=
|
18
|
+
fabricatio/models/tool.py,sha256=PCsX5hdf6YnslkyoPA8FwybGvrO0fJFJpHsheBwg2bo,4886
|
18
19
|
fabricatio/models/events.py,sha256=S0E7l5iQoJYdUn0pSSziHdXqPzIvvLy8ifVPQxXeAho,2570
|
19
20
|
fabricatio/models/utils.py,sha256=u-eR_v-o0BSFSmCprP3mOyAO-WOyg_P68jjzLjyit_w,2457
|
20
21
|
fabricatio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -23,7 +24,7 @@ fabricatio/actions/__init__.py,sha256=eLa_5ACZ-FqdrLtOfCHk5nQBxzhIs1kgMIXWmkm2P8
|
|
23
24
|
fabricatio/actions/communication.py,sha256=4hNzyv5_j4HU291dDuBmBEb66VihQPI9SLRVZrxWu1Y,412
|
24
25
|
fabricatio/actions/transmission.py,sha256=gLLKoi4keL64uaEkHDxwVrBGciheupQrO2fW3GkjfEw,1156
|
25
26
|
fabricatio/_rust.pyi,sha256=EwMPoCZFOCYZ5h_9PZLvO3YrgBEG0Hwae0ux0hcBabM,1487
|
26
|
-
fabricatio/parser.py,sha256=
|
27
|
-
fabricatio/_rust.cpython-312-x86_64-linux-gnu.so,sha256=
|
28
|
-
fabricatio-0.2.0.
|
29
|
-
fabricatio-0.2.0.
|
27
|
+
fabricatio/parser.py,sha256=Ef-uOmrx-1wQqNlcPyPf_LgKg4WLuCzjWgbHGtTTK5o,3190
|
28
|
+
fabricatio/_rust.cpython-312-x86_64-linux-gnu.so,sha256=MXQf097U_QTbRfeJjDbsmUt68b-5bXBUmgIIRNuTQ7w,1189720
|
29
|
+
fabricatio-0.2.0.dev13.data/scripts/tdown,sha256=Rzx0OwwHeu8DOmxOeyI_3m4EmyU70iWG4oR8NgLmoes,4549888
|
30
|
+
fabricatio-0.2.0.dev13.dist-info/RECORD,,
|
Binary file
|
File without changes
|
File without changes
|