fabricatio 0.2.5.dev4__tar.gz → 0.2.6.dev0__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.
Files changed (111) hide show
  1. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/PKG-INFO +2 -1
  2. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/extract_and_review/extract_and_review.py +7 -2
  3. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/minor/hello_fabricatio.py +1 -1
  4. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/pyproject.toml +3 -1
  5. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/actions/article.py +4 -4
  6. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/actions/output.py +1 -3
  7. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/actions/rag.py +3 -3
  8. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/capabilities/propose.py +14 -20
  9. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/capabilities/rag.py +17 -14
  10. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/capabilities/rating.py +41 -36
  11. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/capabilities/review.py +8 -9
  12. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/capabilities/task.py +8 -9
  13. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/config.py +30 -4
  14. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/fs/readers.py +1 -1
  15. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/journal.py +1 -0
  16. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/models/action.py +3 -3
  17. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/models/events.py +6 -4
  18. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/models/extra.py +19 -16
  19. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/models/generic.py +41 -6
  20. fabricatio-0.2.6.dev0/python/fabricatio/models/kwargs_types.py +147 -0
  21. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/models/tool.py +4 -4
  22. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/models/usages.py +101 -75
  23. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/parser.py +26 -5
  24. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/create_json_obj.hbs +0 -8
  25. fabricatio-0.2.6.dev0/templates.tar.gz +0 -0
  26. fabricatio-0.2.6.dev0/uv.lock +1547 -0
  27. fabricatio-0.2.5.dev4/python/fabricatio/models/kwargs_types.py +0 -149
  28. fabricatio-0.2.5.dev4/templates.tar.gz +0 -0
  29. fabricatio-0.2.5.dev4/uv.lock +0 -1509
  30. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/.github/workflows/build-package.yaml +0 -0
  31. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/.github/workflows/ruff.yaml +0 -0
  32. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/.github/workflows/tests.yaml +0 -0
  33. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/.gitignore +0 -0
  34. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/.python-version +0 -0
  35. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/Cargo.lock +0 -0
  36. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/Cargo.toml +0 -0
  37. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/LICENSE +0 -0
  38. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/Makefile +0 -0
  39. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/README.md +0 -0
  40. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/extract_and_review/.gitignore +0 -0
  41. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/extract_article/extract.py +0 -0
  42. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/llm_usages/llm_usage.py +0 -0
  43. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/make_a_rating/rating.py +0 -0
  44. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/make_diary/commits.json +0 -0
  45. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/make_diary/diary.py +0 -0
  46. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/propose_task/propose.py +0 -0
  47. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/reviewer/review.py +0 -0
  48. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/simple_chat/chat.py +0 -0
  49. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/simple_rag/simple_rag.py +0 -0
  50. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/task_handle/handle_task.py +0 -0
  51. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/write_outline/.gitignore +0 -0
  52. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/examples/write_outline/write_outline.py +0 -0
  53. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/__init__.py +0 -0
  54. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/_rust.pyi +0 -0
  55. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/_rust_instances.py +0 -0
  56. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/core.py +0 -0
  57. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/decorators.py +0 -0
  58. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/fs/__init__.py +0 -0
  59. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/fs/curd.py +0 -0
  60. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/models/role.py +0 -0
  61. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/models/task.py +0 -0
  62. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/models/utils.py +0 -0
  63. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/py.typed +0 -0
  64. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/toolboxes/__init__.py +0 -0
  65. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/toolboxes/arithmetic.py +0 -0
  66. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/toolboxes/fs.py +0 -0
  67. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/workflows/articles.py +0 -0
  68. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/python/fabricatio/workflows/rag.py +0 -0
  69. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/src/bib_tools.rs +0 -0
  70. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/src/hash.rs +0 -0
  71. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/src/hbs_helpers.rs +0 -0
  72. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/src/lib.rs +0 -0
  73. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/src/templates.rs +0 -0
  74. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/binary-exploitation-ctf-solver.hbs +0 -0
  75. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/claude-xml.hbs +0 -0
  76. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/clean-up-code.hbs +0 -0
  77. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/cryptography-ctf-solver.hbs +0 -0
  78. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/dependencies.hbs +0 -0
  79. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/document-the-code.hbs +0 -0
  80. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/draft_rating_criteria.hbs +0 -0
  81. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/draft_rating_manual.hbs +0 -0
  82. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/draft_rating_weights_klee.hbs +0 -0
  83. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/draft_tool_usage_code.hbs +0 -0
  84. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/extract_criteria_from_reasons.hbs +0 -0
  85. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/extract_reasons_from_examples.hbs +0 -0
  86. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/find-security-vulnerabilities.hbs +0 -0
  87. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/fix-bugs.hbs +0 -0
  88. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/improve-performance.hbs +0 -0
  89. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/liststr.hbs +0 -0
  90. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/make_choice.hbs +0 -0
  91. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/make_judgment.hbs +0 -0
  92. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/pathstr.hbs +0 -0
  93. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/rate_fine_grind.hbs +0 -0
  94. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/refactor.hbs +0 -0
  95. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/refined_query.hbs +0 -0
  96. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/retrieved_display.hbs +0 -0
  97. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/reverse-engineering-ctf-solver.hbs +0 -0
  98. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/review_string.hbs +0 -0
  99. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/task_briefing.hbs +0 -0
  100. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/web-ctf-solver.hbs +0 -0
  101. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/write-git-commit.hbs +0 -0
  102. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/write-github-pull-request.hbs +0 -0
  103. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/templates/built-in/write-github-readme.hbs +0 -0
  104. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/tests/test_config.py +0 -0
  105. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/tests/test_models/test_action.py +0 -0
  106. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/tests/test_models/test_advanced.py +0 -0
  107. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/tests/test_models/test_generic.py +0 -0
  108. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/tests/test_models/test_role.py +0 -0
  109. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/tests/test_models/test_task.py +0 -0
  110. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/tests/test_models/test_tool.py +0 -0
  111. {fabricatio-0.2.5.dev4 → fabricatio-0.2.6.dev0}/tests/test_models/test_usages.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fabricatio
3
- Version: 0.2.5.dev4
3
+ Version: 0.2.6.dev0
4
4
  Classifier: License :: OSI Approved :: MIT License
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: Programming Language :: Python :: 3.12
@@ -11,6 +11,7 @@ Classifier: Typing :: Typed
11
11
  Requires-Dist: appdirs>=1.4.4
12
12
  Requires-Dist: asyncio>=3.4.3
13
13
  Requires-Dist: asyncstdlib>=3.13.0
14
+ Requires-Dist: json-repair>=0.39.1
14
15
  Requires-Dist: litellm>=1.60.0
15
16
  Requires-Dist: loguru>=0.7.3
16
17
  Requires-Dist: magika>=0.5.1
@@ -25,8 +25,13 @@ async def main() -> None:
25
25
  "Extract the essence of the article from the files in './bpdf_out'",
26
26
  )
27
27
 
28
- ess = await task.override_dependencies(gather_files("bpdf_out", "md")).delegate("article")
29
- logger.success(f"Essence Count:{len(ess)}")
28
+ unchecked_ess = await task.override_dependencies(gather_files("bpdf_out", "md")).delegate("article")
29
+
30
+ if unchecked_ess is None:
31
+ logger.error("No essence found")
32
+ return
33
+ ess = list(filter(lambda x: x is not None, unchecked_ess))
34
+ logger.success(f"Essence Count:{len(ess)}, invalid count: {len(unchecked_ess) - len(ess)}")
30
35
 
31
36
  Path("output").mkdir(exist_ok=True)
32
37
  for i, e in enumerate(ess):
@@ -13,7 +13,7 @@ class Hello(Action):
13
13
 
14
14
  output_key: str = "task_output"
15
15
 
16
- async def _execute(self, task_input: Task[str], **_) -> Any:
16
+ async def _execute(self, **_) -> Any:
17
17
  ret = "Hello fabricatio!"
18
18
  logger.info("executing talk action")
19
19
  return ret
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fabricatio"
3
- version = "0.2.5-dev4"
3
+ version = "0.2.6-dev0"
4
4
  description = "A LLM multi-agent framework."
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
@@ -30,6 +30,7 @@ dependencies = [
30
30
  "appdirs>=1.4.4",
31
31
  "asyncio>=3.4.3",
32
32
  "asyncstdlib>=3.13.0",
33
+ "json-repair>=0.39.1",
33
34
  "litellm>=1.60.0",
34
35
  "loguru>=0.7.3",
35
36
  "magika>=0.5.1",
@@ -71,6 +72,7 @@ dev = [
71
72
  "pytest-mock>=3.14.0",
72
73
  "pytest-rerunfailures>=15.0",
73
74
  "pytest-xdist>=3.6.1",
75
+ "viztracer>=1.0.2",
74
76
  ]
75
77
 
76
78
  [project.optional-dependencies]
@@ -2,7 +2,7 @@
2
2
 
3
3
  from os import PathLike
4
4
  from pathlib import Path
5
- from typing import Callable, List
5
+ from typing import Callable, List, Optional
6
6
 
7
7
  from fabricatio.fs import safe_text_read
8
8
  from fabricatio.journal import logger
@@ -27,7 +27,7 @@ class ExtractArticleEssence(Action):
27
27
  task_input: Task,
28
28
  reader: Callable[[P], str] = lambda p: Path(p).read_text(encoding="utf-8"),
29
29
  **_,
30
- ) -> List[ArticleEssence]:
30
+ ) -> Optional[List[ArticleEssence]]:
31
31
  if not task_input.dependencies:
32
32
  logger.info(err := "Task not approved, since no dependencies are provided.")
33
33
  raise RuntimeError(err)
@@ -51,7 +51,7 @@ class GenerateArticleProposal(Action):
51
51
  self,
52
52
  task_input: Task,
53
53
  **_,
54
- ) -> ArticleProposal:
54
+ ) -> Optional[ArticleProposal]:
55
55
  input_path = await self.awhich_pathstr(
56
56
  f"{task_input.briefing}\nExtract the path of file, which contains the article briefing that I need to read."
57
57
  )
@@ -73,7 +73,7 @@ class GenerateOutline(Action):
73
73
  self,
74
74
  article_proposal: ArticleProposal,
75
75
  **_,
76
- ) -> ArticleOutline:
76
+ ) -> Optional[ArticleOutline]:
77
77
  return await self.propose(
78
78
  ArticleOutline,
79
79
  article_proposal.display(),
@@ -1,7 +1,5 @@
1
1
  """Dump the finalized output to a file."""
2
2
 
3
- from typing import Unpack
4
-
5
3
  from fabricatio.models.action import Action
6
4
  from fabricatio.models.generic import FinalizedDumpAble
7
5
  from fabricatio.models.task import Task
@@ -12,7 +10,7 @@ class DumpFinalizedOutput(Action):
12
10
 
13
11
  output_key: str = "dump_path"
14
12
 
15
- async def _execute(self, task_input: Task, to_dump: FinalizedDumpAble, **cxt: Unpack) -> str:
13
+ async def _execute(self, task_input: Task, to_dump: FinalizedDumpAble, **_) -> str:
16
14
  dump_path = await self.awhich_pathstr(
17
15
  f"{task_input.briefing}\n\nExtract a single path of the file, to which I will dump the data."
18
16
  )
@@ -1,6 +1,6 @@
1
1
  """Inject data into the database."""
2
2
 
3
- from typing import List, Optional, Unpack
3
+ from typing import List, Optional
4
4
 
5
5
  from fabricatio.capabilities.rag import RAG
6
6
  from fabricatio.models.action import Action
@@ -13,8 +13,8 @@ class InjectToDB(Action, RAG):
13
13
  output_key: str = "collection_name"
14
14
 
15
15
  async def _execute[T: PrepareVectorization](
16
- self, to_inject: T | List[T], collection_name: Optional[str] = "my_collection", **cxt: Unpack
17
- ) -> str:
16
+ self, to_inject: T | List[T], collection_name: Optional[str] = "my_collection", **_
17
+ ) -> Optional[str]:
18
18
  if not isinstance(to_inject, list):
19
19
  to_inject = [to_inject]
20
20
 
@@ -1,37 +1,37 @@
1
1
  """A module for the task capabilities of the Fabricatio library."""
2
2
 
3
- from typing import List, Type, Unpack, overload
3
+ from typing import List, Optional, Type, Unpack, overload
4
4
 
5
5
  from fabricatio.models.generic import ProposedAble
6
- from fabricatio.models.kwargs_types import GenerateKwargs
6
+ from fabricatio.models.kwargs_types import ValidateKwargs
7
7
  from fabricatio.models.usages import LLMUsage
8
8
 
9
9
 
10
- class Propose[M: ProposedAble](LLMUsage):
10
+ class Propose(LLMUsage):
11
11
  """A class that proposes an Obj based on a prompt."""
12
12
 
13
13
  @overload
14
- async def propose(
14
+ async def propose[M: ProposedAble](
15
15
  self,
16
16
  cls: Type[M],
17
17
  prompt: List[str],
18
- **kwargs: Unpack[GenerateKwargs[M]],
19
- ) -> List[M]: ...
18
+ **kwargs: Unpack[ValidateKwargs[M]],
19
+ ) -> Optional[List[M]]: ...
20
20
 
21
21
  @overload
22
- async def propose(
22
+ async def propose[M: ProposedAble](
23
23
  self,
24
24
  cls: Type[M],
25
25
  prompt: str,
26
- **kwargs: Unpack[GenerateKwargs[M]],
27
- ) -> M: ...
26
+ **kwargs: Unpack[ValidateKwargs[M]],
27
+ ) -> Optional[M]: ...
28
28
 
29
- async def propose(
29
+ async def propose[M: ProposedAble](
30
30
  self,
31
31
  cls: Type[M],
32
32
  prompt: List[str] | str,
33
- **kwargs: Unpack[GenerateKwargs[M]],
34
- ) -> List[M] | M:
33
+ **kwargs: Unpack[ValidateKwargs[M]],
34
+ ) -> Optional[List[M] | M]:
35
35
  """Asynchronously proposes a task based on a given prompt and parameters.
36
36
 
37
37
  Parameters:
@@ -42,14 +42,8 @@ class Propose[M: ProposedAble](LLMUsage):
42
42
  Returns:
43
43
  A Task object based on the proposal result.
44
44
  """
45
- if isinstance(prompt, str):
46
- return await self.aask_validate(
47
- question=cls.create_json_prompt(prompt),
48
- validator=cls.instantiate_from_string,
49
- **kwargs,
50
- )
51
- return await self.aask_validate_batch(
52
- questions=[cls.create_json_prompt(p) for p in prompt],
45
+ return await self.aask_validate(
46
+ question=cls.create_json_prompt(prompt),
53
47
  validator=cls.instantiate_from_string,
54
48
  **kwargs,
55
49
  )
@@ -8,7 +8,7 @@ from functools import lru_cache
8
8
  from operator import itemgetter
9
9
  from os import PathLike
10
10
  from pathlib import Path
11
- from typing import Any, Callable, Dict, List, Optional, Self, Union, Unpack, overload
11
+ from typing import Any, Callable, Dict, List, Optional, Self, Union, Unpack, cast, overload
12
12
 
13
13
  from fabricatio._rust_instances import template_manager
14
14
  from fabricatio.config import configs
@@ -111,9 +111,9 @@ class RAG(EmbeddingUsage):
111
111
  create (bool): Whether to create the collection if it does not exist.
112
112
  **kwargs (Unpack[CollectionSimpleConfigKwargs]): Additional keyword arguments for collection configuration.
113
113
  """
114
- if create and collection_name and not self._client.has_collection(collection_name):
114
+ if create and collection_name and self.client.has_collection(collection_name):
115
115
  kwargs["dimension"] = kwargs.get("dimension") or self.milvus_dimensions or configs.rag.milvus_dimensions
116
- self._client.create_collection(collection_name, auto_id=True, **kwargs)
116
+ self.client.create_collection(collection_name, auto_id=True, **kwargs)
117
117
  logger.info(f"Creating collection {collection_name}")
118
118
 
119
119
  self.target_collection = collection_name
@@ -152,15 +152,17 @@ class RAG(EmbeddingUsage):
152
152
  Self: The current instance, allowing for method chaining.
153
153
  """
154
154
  if isinstance(data, MilvusData):
155
- data = data.prepare_insertion()
156
- if isinstance(data, list):
157
- data = [d.prepare_insertion() if isinstance(d, MilvusData) else d for d in data]
155
+ prepared_data = data.prepare_insertion()
156
+ elif isinstance(data, list):
157
+ prepared_data = [d.prepare_insertion() if isinstance(d, MilvusData) else d for d in data]
158
+ else:
159
+ raise TypeError(f"Expected MilvusData or list of MilvusData, got {type(data)}")
158
160
  c_name = collection_name or self.safe_target_collection
159
- self._client.insert(c_name, data)
161
+ self.client.insert(c_name, prepared_data)
160
162
 
161
163
  if flush:
162
164
  logger.debug(f"Flushing collection {c_name}")
163
- self._client.flush(c_name)
165
+ self.client.flush(c_name)
164
166
  return self
165
167
 
166
168
  async def consume_file(
@@ -196,14 +198,14 @@ class RAG(EmbeddingUsage):
196
198
  self.add_document(await self.pack(text), collection_name or self.safe_target_collection, flush=True)
197
199
  return self
198
200
 
199
- async def afetch_document(
201
+ async def afetch_document[V: (int, str, float, bytes)](
200
202
  self,
201
203
  vecs: List[List[float]],
202
204
  desired_fields: List[str] | str,
203
205
  collection_name: Optional[str] = None,
204
206
  similarity_threshold: float = 0.37,
205
207
  result_per_query: int = 10,
206
- ) -> List[Dict[str, Any]] | List[Any]:
208
+ ) -> List[Dict[str, Any]] | List[V]:
207
209
  """Fetch data from the collection.
208
210
 
209
211
  Args:
@@ -217,7 +219,7 @@ class RAG(EmbeddingUsage):
217
219
  List[Dict[str, Any]] | List[Any]: The retrieved data.
218
220
  """
219
221
  # Step 1: Search for vectors
220
- search_results = self._client.search(
222
+ search_results = self.client.search(
221
223
  collection_name or self.safe_target_collection,
222
224
  vecs,
223
225
  search_params={"radius": similarity_threshold},
@@ -237,7 +239,7 @@ class RAG(EmbeddingUsage):
237
239
 
238
240
  if isinstance(desired_fields, list):
239
241
  return resp
240
- return [r.get(desired_fields) for r in resp]
242
+ return [r.get(desired_fields) for r in resp] # extract the single field as list
241
243
 
242
244
  async def aretrieve(
243
245
  self,
@@ -257,12 +259,13 @@ class RAG(EmbeddingUsage):
257
259
  """
258
260
  if isinstance(query, str):
259
261
  query = [query]
260
- return (
262
+ return cast(
263
+ List[str],
261
264
  await self.afetch_document(
262
265
  vecs=(await self.vectorize(query)),
263
266
  desired_fields="text",
264
267
  **kwargs,
265
- )
268
+ ),
266
269
  )[:final_limit]
267
270
 
268
271
  async def aask_retrieved(
@@ -1,15 +1,14 @@
1
1
  """A module that provides functionality to rate tasks based on a rating manual and score range."""
2
2
 
3
- from asyncio import gather
4
3
  from itertools import permutations
5
4
  from random import sample
6
- from typing import Dict, List, Set, Tuple, Union, Unpack, overload
5
+ from typing import Dict, List, Optional, Set, Tuple, Union, Unpack, overload
7
6
 
8
7
  from fabricatio._rust_instances import template_manager
9
8
  from fabricatio.config import configs
10
9
  from fabricatio.journal import logger
11
10
  from fabricatio.models.generic import WithBriefing
12
- from fabricatio.models.kwargs_types import GenerateKwargs, ValidateKwargs
11
+ from fabricatio.models.kwargs_types import ValidateKwargs
13
12
  from fabricatio.models.usages import LLMUsage
14
13
  from fabricatio.parser import JsonCapture
15
14
  from more_itertools import flatten, windowed
@@ -25,11 +24,11 @@ class GiveRating(WithBriefing, LLMUsage):
25
24
 
26
25
  async def rate_fine_grind(
27
26
  self,
28
- to_rate: str,
27
+ to_rate: str | List[str],
29
28
  rating_manual: Dict[str, str],
30
29
  score_range: Tuple[float, float],
31
- **kwargs: Unpack[ValidateKwargs],
32
- ) -> Dict[str, float]:
30
+ **kwargs: Unpack[ValidateKwargs[Dict[str, float]]],
31
+ ) -> Optional[Dict[str, float] | List[Dict[str, float]]]:
33
32
  """Rate a given string based on a rating manual and score range.
34
33
 
35
34
  Args:
@@ -63,9 +62,21 @@ class GiveRating(WithBriefing, LLMUsage):
63
62
  "rating_manual": rating_manual,
64
63
  },
65
64
  )
66
- ),
65
+ )
66
+ if isinstance(to_rate, str)
67
+ else [
68
+ template_manager.render_template(
69
+ configs.templates.rate_fine_grind_template,
70
+ {
71
+ "to_rate": item,
72
+ "min_score": score_range[0],
73
+ "max_score": score_range[1],
74
+ "rating_manual": rating_manual,
75
+ },
76
+ )
77
+ for item in to_rate
78
+ ],
67
79
  validator=_validator,
68
- system_message=f"# your personal briefing: \n{self.briefing}",
69
80
  **kwargs,
70
81
  )
71
82
 
@@ -96,7 +107,7 @@ class GiveRating(WithBriefing, LLMUsage):
96
107
  criteria: Set[str],
97
108
  score_range: Tuple[float, float] = (0.0, 1.0),
98
109
  **kwargs: Unpack[ValidateKwargs],
99
- ) -> Union[Dict[str, float], List[Dict[str, float]]]:
110
+ ) -> Optional[Dict[str, float] | List[Dict[str, float]]]:
100
111
  """Rate a given string or a sequence of strings based on a topic, criteria, and score range.
101
112
 
102
113
  Args:
@@ -110,16 +121,13 @@ class GiveRating(WithBriefing, LLMUsage):
110
121
  Union[Dict[str, float], List[Dict[str, float]]]: A dictionary with the ratings for each criterion if a single string is provided,
111
122
  or a list of dictionaries with the ratings for each criterion if a sequence of strings is provided.
112
123
  """
113
- manual = await self.draft_rating_manual(topic, criteria, **kwargs)
114
- if isinstance(to_rate, str):
115
- return await self.rate_fine_grind(to_rate, manual, score_range, **kwargs)
116
- if isinstance(to_rate, list):
117
- return await gather(*[self.rate_fine_grind(item, manual, score_range, **kwargs) for item in to_rate])
118
- raise ValueError("to_rate must be a string or a list of strings")
124
+ manual = await self.draft_rating_manual(topic, criteria, **kwargs) or dict(zip(criteria, criteria, strict=True))
125
+
126
+ return await self.rate_fine_grind(to_rate, manual, score_range, **kwargs)
119
127
 
120
128
  async def draft_rating_manual(
121
- self, topic: str, criteria: Set[str], **kwargs: Unpack[ValidateKwargs]
122
- ) -> Dict[str, str]:
129
+ self, topic: str, criteria: Set[str], **kwargs: Unpack[ValidateKwargs[Dict[str, str]]]
130
+ ) -> Optional[Dict[str, str]]:
123
131
  """Drafts a rating manual based on a topic and dimensions.
124
132
 
125
133
  Args:
@@ -151,16 +159,15 @@ class GiveRating(WithBriefing, LLMUsage):
151
159
  )
152
160
  ),
153
161
  validator=_validator,
154
- system_message=f"# your personal briefing: \n{self.briefing}",
155
- **kwargs,
162
+ **self.prepend(kwargs),
156
163
  )
157
164
 
158
165
  async def draft_rating_criteria(
159
166
  self,
160
167
  topic: str,
161
168
  criteria_count: NonNegativeInt = 0,
162
- **kwargs: Unpack[ValidateKwargs],
163
- ) -> Set[str]:
169
+ **kwargs: Unpack[ValidateKwargs[Set[str]]],
170
+ ) -> Optional[Set[str]]:
164
171
  """Drafts rating dimensions based on a topic.
165
172
 
166
173
  Args:
@@ -182,10 +189,9 @@ class GiveRating(WithBriefing, LLMUsage):
182
189
  )
183
190
  ),
184
191
  validator=lambda resp: set(out)
185
- if (out := JsonCapture.validate_with(resp, list, str, criteria_count))
192
+ if (out := JsonCapture.validate_with(resp, list, str, criteria_count)) is not None
186
193
  else out,
187
- system_message=f"# your personal briefing: \n{self.briefing}",
188
- **kwargs,
194
+ **self.prepend(kwargs),
189
195
  )
190
196
 
191
197
  async def draft_rating_criteria_from_examples(
@@ -196,7 +202,7 @@ class GiveRating(WithBriefing, LLMUsage):
196
202
  reasons_count: PositiveInt = 2,
197
203
  criteria_count: PositiveInt = 5,
198
204
  **kwargs: Unpack[ValidateKwargs],
199
- ) -> Set[str]:
205
+ ) -> Optional[Set[str]]:
200
206
  """Asynchronously drafts a set of rating criteria based on provided examples.
201
207
 
202
208
  This function generates rating criteria by analyzing examples and extracting reasons for comparison,
@@ -220,11 +226,10 @@ class GiveRating(WithBriefing, LLMUsage):
220
226
  if m:
221
227
  examples = sample(examples, m)
222
228
 
223
- kwargs = GenerateKwargs(system_message=f"# your personal briefing: \n{self.briefing}", **kwargs)
224
229
  # extract reasons from the comparison of ordered pairs of extracted from examples
225
230
  reasons = flatten(
226
- await self.aask_validate_batch(
227
- questions=[
231
+ await self.aask_validate(
232
+ question=[
228
233
  template_manager.render_template(
229
234
  configs.templates.extract_reasons_from_examples_template,
230
235
  {
@@ -239,7 +244,7 @@ class GiveRating(WithBriefing, LLMUsage):
239
244
  validator=lambda resp: JsonCapture.validate_with(
240
245
  resp, target_type=list, elements_type=str, length=reasons_count
241
246
  ),
242
- **kwargs,
247
+ **self.prepend(kwargs),
243
248
  )
244
249
  )
245
250
  # extract certain mount of criteria from reasons according to their importance and frequency
@@ -264,7 +269,7 @@ class GiveRating(WithBriefing, LLMUsage):
264
269
  self,
265
270
  topic: str,
266
271
  criteria: Set[str],
267
- **kwargs: Unpack[ValidateKwargs],
272
+ **kwargs: Unpack[ValidateKwargs[float]],
268
273
  ) -> Dict[str, float]:
269
274
  """Drafts rating weights for a given topic and criteria using the Klee method.
270
275
 
@@ -279,12 +284,12 @@ class GiveRating(WithBriefing, LLMUsage):
279
284
  if len(criteria) < 2: # noqa: PLR2004
280
285
  raise ValueError("At least two criteria are required to draft rating weights")
281
286
 
282
- criteria = list(criteria) # freeze the order
283
- windows = windowed(criteria, 2)
287
+ criteria_seq = list(criteria) # freeze the order
288
+ windows = windowed(criteria_seq, 2)
284
289
 
285
290
  # get the importance multiplier indicating how important is second criterion compared to the first one
286
- relative_weights = await self.aask_validate_batch(
287
- questions=[
291
+ relative_weights = await self.aask_validate(
292
+ question=[
288
293
  template_manager.render_template(
289
294
  configs.templates.draft_rating_weights_klee_template,
290
295
  {
@@ -296,13 +301,13 @@ class GiveRating(WithBriefing, LLMUsage):
296
301
  for pair in windows
297
302
  ],
298
303
  validator=lambda resp: JsonCapture.validate_with(resp, target_type=float),
299
- **GenerateKwargs(system_message=f"# your personal briefing: \n{self.briefing}", **kwargs),
304
+ **self.prepend(kwargs),
300
305
  )
301
306
  weights = [1]
302
307
  for rw in relative_weights:
303
308
  weights.append(weights[-1] * rw)
304
309
  total = sum(weights)
305
- return dict(zip(criteria, [w / total for w in weights], strict=True))
310
+ return dict(zip(criteria_seq, [w / total for w in weights], strict=True))
306
311
 
307
312
  async def composite_score(
308
313
  self,
@@ -1,15 +1,14 @@
1
1
  """A module that provides functionality to rate tasks based on a rating manual and score range."""
2
2
 
3
- from typing import List, Optional, Self, Set, Unpack
3
+ from typing import List, Optional, Self, Set, Unpack, cast
4
4
 
5
5
  from fabricatio import template_manager
6
6
  from fabricatio.capabilities.propose import Propose
7
7
  from fabricatio.capabilities.rating import GiveRating
8
8
  from fabricatio.config import configs
9
9
  from fabricatio.models.generic import Base, Display, ProposedAble, WithBriefing
10
- from fabricatio.models.kwargs_types import GenerateKwargs, ReviewKwargs
10
+ from fabricatio.models.kwargs_types import ReviewKwargs, ValidateKwargs
11
11
  from fabricatio.models.task import Task
12
- from pydantic import PrivateAttr
13
12
  from questionary import Choice, checkbox
14
13
  from rich import print
15
14
 
@@ -76,7 +75,7 @@ class ReviewResult[T](ProposedAble, Display):
76
75
  problem_solutions: List[ProblemSolutions]
77
76
  """Collection of problems identified during review along with their potential solutions."""
78
77
 
79
- _ref: T = PrivateAttr(None)
78
+ _ref: T
80
79
  """Reference to the original object that was reviewed."""
81
80
 
82
81
  def update_topic(self, topic: str) -> Self:
@@ -100,8 +99,8 @@ class ReviewResult[T](ProposedAble, Display):
100
99
  Returns:
101
100
  ReviewResult[K]: The current instance with updated reference type.
102
101
  """
103
- self._ref = ref
104
- return self
102
+ self._ref = ref # pyright: ignore [reportAttributeAccessIssue]
103
+ return cast(ReviewResult[K], self)
105
104
 
106
105
  def deref(self) -> T:
107
106
  """Retrieve the referenced object that was reviewed.
@@ -178,14 +177,14 @@ class Review(GiveRating, Propose):
178
177
  ReviewResult[Task[T]]: A review result containing identified problems and proposed solutions,
179
178
  with a reference to the original task.
180
179
  """
181
- return await self.review_obj(task, **kwargs)
180
+ return cast(ReviewResult[Task[T]], await self.review_obj(task, **kwargs))
182
181
 
183
182
  async def review_string(
184
183
  self,
185
184
  text: str,
186
185
  topic: str,
187
186
  criteria: Optional[Set[str]] = None,
188
- **kwargs: Unpack[GenerateKwargs[ReviewResult[str]]],
187
+ **kwargs: Unpack[ValidateKwargs[ReviewResult[str]]],
189
188
  ) -> ReviewResult[str]:
190
189
  """Review a string based on specified topic and criteria.
191
190
 
@@ -197,7 +196,7 @@ class Review(GiveRating, Propose):
197
196
  topic (str): The subject topic for the review criteria.
198
197
  criteria (Optional[Set[str]], optional): A set of criteria for the review.
199
198
  If not provided, criteria will be drafted automatically. Defaults to None.
200
- **kwargs (Unpack[GenerateKwargs]): Additional keyword arguments for the LLM usage.
199
+ **kwargs (Unpack[ValidateKwargs]): Additional keyword arguments for the LLM usage.
201
200
 
202
201
  Returns:
203
202
  ReviewResult[str]: A review result containing identified problems and proposed solutions,
@@ -1,19 +1,19 @@
1
1
  """A module for the task capabilities of the Fabricatio library."""
2
2
 
3
3
  from types import CodeType
4
- from typing import Any, Dict, List, Optional, Tuple, Unpack
4
+ from typing import Any, Dict, List, Optional, Tuple, Unpack, cast
5
5
 
6
6
  import orjson
7
7
  from fabricatio._rust_instances import template_manager
8
8
  from fabricatio.capabilities.propose import Propose
9
9
  from fabricatio.config import configs
10
+ from fabricatio.journal import logger
10
11
  from fabricatio.models.generic import WithBriefing
11
12
  from fabricatio.models.kwargs_types import ChooseKwargs, ValidateKwargs
12
13
  from fabricatio.models.task import Task
13
14
  from fabricatio.models.tool import Tool, ToolExecutor
14
15
  from fabricatio.models.usages import ToolBoxUsage
15
16
  from fabricatio.parser import JsonCapture, PythonCapture
16
- from loguru import logger
17
17
 
18
18
 
19
19
  class ProposeTask(WithBriefing, Propose):
@@ -22,7 +22,7 @@ class ProposeTask(WithBriefing, Propose):
22
22
  async def propose_task[T](
23
23
  self,
24
24
  prompt: str,
25
- **kwargs: Unpack[ValidateKwargs],
25
+ **kwargs: Unpack[ValidateKwargs[Task[T]]],
26
26
  ) -> Task[T]:
27
27
  """Asynchronously proposes a task based on a given prompt and parameters.
28
28
 
@@ -37,7 +37,7 @@ class ProposeTask(WithBriefing, Propose):
37
37
  logger.error(err := f"{self.name}: Prompt must be provided.")
38
38
  raise ValueError(err)
39
39
 
40
- return await self.propose(Task, prompt, system_message=f"# your personal briefing: \n{self.briefing}", **kwargs)
40
+ return await self.propose(Task, prompt, **self.prepend(cast(Dict[str, Any], kwargs)))
41
41
 
42
42
 
43
43
  class HandleTask(WithBriefing, ToolBoxUsage):
@@ -49,7 +49,7 @@ class HandleTask(WithBriefing, ToolBoxUsage):
49
49
  tools: List[Tool],
50
50
  data: Dict[str, Any],
51
51
  **kwargs: Unpack[ValidateKwargs],
52
- ) -> Tuple[CodeType, List[str]]:
52
+ ) -> Optional[Tuple[CodeType, List[str]]]:
53
53
  """Asynchronously drafts the tool usage code for a task based on a given task object and tools."""
54
54
  logger.info(f"Drafting tool usage code for task: {task.briefing}")
55
55
 
@@ -81,8 +81,7 @@ class HandleTask(WithBriefing, ToolBoxUsage):
81
81
  return await self.aask_validate(
82
82
  question=q,
83
83
  validator=_validator,
84
- system_message=f"# your personal briefing: \n{self.briefing}",
85
- **kwargs,
84
+ **self.prepend(cast(Dict[str, Any], kwargs)),
86
85
  )
87
86
 
88
87
  async def handle_fin_grind(
@@ -99,10 +98,10 @@ class HandleTask(WithBriefing, ToolBoxUsage):
99
98
  tools = await self.gather_tools_fine_grind(task, box_choose_kwargs, tool_choose_kwargs)
100
99
  logger.info(f"{self.name} have gathered {[t.name for t in tools]}")
101
100
 
102
- if tools:
101
+ if tools and (pack := await self.draft_tool_usage_code(task, tools, data, **kwargs)):
103
102
  executor = ToolExecutor(candidates=tools, data=data)
104
- code, to_extract = await self.draft_tool_usage_code(task, tools, data, **kwargs)
105
103
 
104
+ code, to_extract = pack
106
105
  cxt = executor.execute(code)
107
106
  if to_extract:
108
107
  return tuple(cxt.get(k) for k in to_extract)