fabricatio 0.2.5.dev1__tar.gz → 0.2.5.dev3__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 (116) hide show
  1. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/Cargo.lock +17 -0
  2. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/Cargo.toml +1 -0
  3. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/PKG-INFO +1 -2
  4. fabricatio-0.2.5.dev3/examples/extract_and_review/.gitignore +1 -0
  5. fabricatio-0.2.5.dev3/examples/extract_and_review/extract_and_review.py +37 -0
  6. fabricatio-0.2.5.dev3/examples/reviewer/review.py +27 -0
  7. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/pyproject.toml +1 -2
  8. fabricatio-0.2.5.dev3/python/fabricatio/_rust.pyi +102 -0
  9. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/_rust_instances.py +2 -0
  10. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/capabilities/propose.py +3 -3
  11. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/capabilities/rating.py +15 -3
  12. fabricatio-0.2.5.dev3/python/fabricatio/capabilities/review.py +242 -0
  13. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/config.py +19 -0
  14. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/fs/__init__.py +2 -0
  15. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/fs/curd.py +13 -0
  16. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/journal.py +0 -1
  17. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/models/action.py +3 -4
  18. fabricatio-0.2.5.dev3/python/fabricatio/models/kwargs_types.py +146 -0
  19. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/models/role.py +1 -1
  20. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/models/usages.py +53 -55
  21. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/toolboxes/fs.py +2 -0
  22. fabricatio-0.2.5.dev3/src/bib_tools.rs +73 -0
  23. fabricatio-0.2.5.dev3/src/hbs_helpers.rs +9 -0
  24. fabricatio-0.2.5.dev3/src/templates.rs +104 -0
  25. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/create_json_obj.hbs +16 -2
  26. fabricatio-0.2.5.dev3/templates/built-in/review_string.hbs +22 -0
  27. fabricatio-0.2.5.dev3/templates.tar.gz +0 -0
  28. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/uv.lock +1 -9
  29. fabricatio-0.2.5.dev1/python/fabricatio/_rust.pyi +0 -61
  30. fabricatio-0.2.5.dev1/python/fabricatio/capabilities/review.py +0 -141
  31. fabricatio-0.2.5.dev1/python/fabricatio/models/kwargs_types.py +0 -67
  32. fabricatio-0.2.5.dev1/src/bib_tools.rs +0 -45
  33. fabricatio-0.2.5.dev1/src/hbs_helpers.rs +0 -15
  34. fabricatio-0.2.5.dev1/src/templates.rs +0 -105
  35. fabricatio-0.2.5.dev1/templates/built-in/review_string.hbs +0 -14
  36. fabricatio-0.2.5.dev1/templates.tar.gz +0 -0
  37. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/.github/workflows/build-package.yaml +0 -0
  38. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/.github/workflows/ruff.yaml +0 -0
  39. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/.github/workflows/tests.yaml +0 -0
  40. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/.gitignore +0 -0
  41. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/.python-version +0 -0
  42. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/LICENSE +0 -0
  43. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/Makefile +0 -0
  44. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/README.md +0 -0
  45. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/examples/extract_article/extract.py +0 -0
  46. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/examples/llm_usages/llm_usage.py +0 -0
  47. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/examples/make_a_rating/rating.py +0 -0
  48. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/examples/make_diary/commits.json +0 -0
  49. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/examples/make_diary/diary.py +0 -0
  50. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/examples/minor/hello_fabricatio.py +0 -0
  51. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/examples/propose_task/propose.py +0 -0
  52. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/examples/simple_chat/chat.py +0 -0
  53. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/examples/simple_rag/simple_rag.py +0 -0
  54. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/examples/task_handle/handle_task.py +0 -0
  55. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/examples/write_outline/.gitignore +0 -0
  56. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/examples/write_outline/write_outline.py +0 -0
  57. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/__init__.py +0 -0
  58. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/actions/article.py +0 -0
  59. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/actions/output.py +0 -0
  60. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/actions/rag.py +0 -0
  61. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/capabilities/rag.py +0 -0
  62. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/capabilities/task.py +0 -0
  63. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/core.py +0 -0
  64. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/decorators.py +0 -0
  65. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/fs/readers.py +0 -0
  66. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/models/events.py +0 -0
  67. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/models/extra.py +0 -0
  68. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/models/generic.py +0 -0
  69. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/models/task.py +0 -0
  70. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/models/tool.py +0 -0
  71. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/models/utils.py +0 -0
  72. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/parser.py +0 -0
  73. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/py.typed +0 -0
  74. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/toolboxes/__init__.py +0 -0
  75. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/toolboxes/arithmetic.py +0 -0
  76. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/workflows/articles.py +0 -0
  77. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/python/fabricatio/workflows/rag.py +0 -0
  78. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/src/hash.rs +0 -0
  79. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/src/lib.rs +0 -0
  80. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/binary-exploitation-ctf-solver.hbs +0 -0
  81. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/claude-xml.hbs +0 -0
  82. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/clean-up-code.hbs +0 -0
  83. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/cryptography-ctf-solver.hbs +0 -0
  84. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/dependencies.hbs +0 -0
  85. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/document-the-code.hbs +0 -0
  86. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/draft_rating_criteria.hbs +0 -0
  87. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/draft_rating_manual.hbs +0 -0
  88. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/draft_rating_weights_klee.hbs +0 -0
  89. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/draft_tool_usage_code.hbs +0 -0
  90. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/extract_criteria_from_reasons.hbs +0 -0
  91. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/extract_reasons_from_examples.hbs +0 -0
  92. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/find-security-vulnerabilities.hbs +0 -0
  93. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/fix-bugs.hbs +0 -0
  94. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/improve-performance.hbs +0 -0
  95. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/liststr.hbs +0 -0
  96. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/make_choice.hbs +0 -0
  97. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/make_judgment.hbs +0 -0
  98. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/pathstr.hbs +0 -0
  99. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/rate_fine_grind.hbs +0 -0
  100. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/refactor.hbs +0 -0
  101. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/refined_query.hbs +0 -0
  102. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/retrieved_display.hbs +0 -0
  103. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/reverse-engineering-ctf-solver.hbs +0 -0
  104. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/task_briefing.hbs +0 -0
  105. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/web-ctf-solver.hbs +0 -0
  106. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/write-git-commit.hbs +0 -0
  107. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/write-github-pull-request.hbs +0 -0
  108. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/templates/built-in/write-github-readme.hbs +0 -0
  109. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/tests/test_config.py +0 -0
  110. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/tests/test_models/test_action.py +0 -0
  111. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/tests/test_models/test_advanced.py +0 -0
  112. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/tests/test_models/test_generic.py +0 -0
  113. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/tests/test_models/test_role.py +0 -0
  114. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/tests/test_models/test_task.py +0 -0
  115. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/tests/test_models/test_tool.py +0 -0
  116. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev3}/tests/test_models/test_usages.py +0 -0
@@ -448,6 +448,7 @@ dependencies = [
448
448
  "biblatex",
449
449
  "blake3",
450
450
  "handlebars",
451
+ "nucleo-matcher",
451
452
  "pyo3",
452
453
  "pythonize",
453
454
  "rayon",
@@ -1052,6 +1053,16 @@ dependencies = [
1052
1053
  "tempfile",
1053
1054
  ]
1054
1055
 
1056
+ [[package]]
1057
+ name = "nucleo-matcher"
1058
+ version = "0.3.1"
1059
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1060
+ checksum = "bf33f538733d1a5a3494b836ba913207f14d9d4a1d3cd67030c5061bdd2cac85"
1061
+ dependencies = [
1062
+ "memchr",
1063
+ "unicode-segmentation",
1064
+ ]
1065
+
1055
1066
  [[package]]
1056
1067
  name = "num-modular"
1057
1068
  version = "0.6.1"
@@ -1913,6 +1924,12 @@ dependencies = [
1913
1924
  "tinyvec",
1914
1925
  ]
1915
1926
 
1927
+ [[package]]
1928
+ name = "unicode-segmentation"
1929
+ version = "1.12.0"
1930
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1931
+ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
1932
+
1916
1933
  [[package]]
1917
1934
  name = "unindent"
1918
1935
  version = "0.2.3"
@@ -9,6 +9,7 @@ crate-type = ["cdylib"]
9
9
  biblatex = "0.10.0"
10
10
  blake3 = "1.6.0"
11
11
  handlebars = "6.3.1"
12
+ nucleo-matcher = "0.3.1"
12
13
  pyo3 = { version = "0.23.4", features = ["extension-module"] }
13
14
  pythonize = "0.23.0"
14
15
  rayon = "1.10.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fabricatio
3
- Version: 0.2.5.dev1
3
+ Version: 0.2.5.dev3
4
4
  Classifier: License :: OSI Approved :: MIT License
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: Programming Language :: Python :: 3.12
@@ -9,7 +9,6 @@ Classifier: Framework :: AsyncIO
9
9
  Classifier: Framework :: Pydantic :: 2
10
10
  Classifier: Typing :: Typed
11
11
  Requires-Dist: appdirs>=1.4.4
12
- Requires-Dist: async-cache>=1.1.1
13
12
  Requires-Dist: asyncio>=3.4.3
14
13
  Requires-Dist: asyncstdlib>=3.13.0
15
14
  Requires-Dist: litellm>=1.60.0
@@ -0,0 +1,37 @@
1
+ """Example of proposing a task to a role."""
2
+
3
+ import asyncio
4
+ from pathlib import Path
5
+ from typing import List
6
+
7
+ from fabricatio import ArticleEssence, Event, ExtractArticleEssence, Role, Task, WorkFlow, logger
8
+ from fabricatio.fs.curd import dump_text, gather_files
9
+
10
+
11
+ async def main() -> None:
12
+ """Main function."""
13
+ role = Role(
14
+ name="Researcher",
15
+ description="Extract article essence",
16
+ registry={
17
+ Event.quick_instantiate("article"): WorkFlow(
18
+ name="extract",
19
+ steps=(ExtractArticleEssence(output_key="task_output"),),
20
+ )
21
+ },
22
+ )
23
+
24
+ task: Task[List[ArticleEssence]] = await role.propose_task(
25
+ "Extract the essence of the article from the files in './bpdf_out'",
26
+ )
27
+
28
+ ess = await task.override_dependencies(gather_files("bpdf_out", "md")).delegate("article")
29
+ logger.success(f"Essence Count:{len(ess)}")
30
+
31
+ Path("output").mkdir(exist_ok=True)
32
+ for i, e in enumerate(ess):
33
+ dump_text(f"output/{i}.json", e.display())
34
+
35
+
36
+ if __name__ == "__main__":
37
+ asyncio.run(main())
@@ -0,0 +1,27 @@
1
+ """Example of review usage."""
2
+
3
+ import asyncio
4
+
5
+ from fabricatio import Role, logger
6
+
7
+
8
+ async def main() -> None:
9
+ """Main function."""
10
+ role = Role(
11
+ name="Reviewer",
12
+ description="A role that reviews the code.",
13
+ )
14
+
15
+ code = await role.aask(
16
+ "write a cli app using rust with clap which can generate a basic manifest of a standard rust project, output code only,no extra explanation"
17
+ )
18
+
19
+ logger.success(f"Code: \n{code}")
20
+ res = await role.review_string(code, "If the cli app is of good design")
21
+ logger.success(f"Review: \n{res.display()}")
22
+ await res.supervisor_check(True)
23
+ logger.success(f"Review: \n{res.display()}")
24
+
25
+
26
+ if __name__ == "__main__":
27
+ asyncio.run(main())
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fabricatio"
3
- version = "0.2.5-dev1"
3
+ version = "0.2.5-dev3"
4
4
  description = "A LLM multi-agent framework."
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
@@ -28,7 +28,6 @@ keywords = [
28
28
  requires-python = ">=3.12,<3.13"
29
29
  dependencies = [
30
30
  "appdirs>=1.4.4",
31
- "async-cache>=1.1.1",
32
31
  "asyncio>=3.4.3",
33
32
  "asyncstdlib>=3.13.0",
34
33
  "litellm>=1.60.0",
@@ -0,0 +1,102 @@
1
+ from pathlib import Path
2
+ from typing import Any, Dict, List, Optional
3
+
4
+ class TemplateManager:
5
+ """Template rendering engine using Handlebars templates.
6
+
7
+ This manager handles template discovery, loading, and rendering
8
+ through a wrapper around the handlebars-rust engine.
9
+
10
+ See: https://crates.io/crates/handlebars
11
+ """
12
+ def __init__(
13
+ self, template_dirs: List[Path], suffix: Optional[str] = None, active_loading: Optional[bool] = None
14
+ ) -> None:
15
+ """Initialize the template manager.
16
+
17
+ Args:
18
+ template_dirs: List of directories containing template files
19
+ suffix: File extension for templates (defaults to 'hbs')
20
+ active_loading: Whether to enable dev mode for reloading templates on change
21
+ """
22
+
23
+ @property
24
+ def template_count(self) -> int:
25
+ """Returns the number of currently loaded templates."""
26
+
27
+ def get_template_source(self, name: str) -> Optional[str]:
28
+ """Get the filesystem path for a template.
29
+
30
+ Args:
31
+ name: Template name (without extension)
32
+
33
+ Returns:
34
+ Path to the template file if found, None otherwise
35
+ """
36
+
37
+ def discover_templates(self) -> None:
38
+ """Scan template directories and load available templates.
39
+
40
+ This refreshes the template cache, finding any new or modified templates.
41
+ """
42
+
43
+ def render_template(self, name: str, data: Dict[str, Any]) -> str:
44
+ """Render a template with context data.
45
+
46
+ Args:
47
+ name: Template name (without extension)
48
+ data: Context dictionary to provide variables to the template
49
+
50
+ Returns:
51
+ Rendered template content as string
52
+
53
+ Raises:
54
+ RuntimeError: If template rendering fails
55
+ """
56
+
57
+ def blake3_hash(content: bytes) -> str:
58
+ """Calculate the BLAKE3 cryptographic hash of data.
59
+
60
+ Args:
61
+ content: Bytes to be hashed
62
+
63
+ Returns:
64
+ Hex-encoded BLAKE3 hash string
65
+ """
66
+
67
+ class BibManager:
68
+ """BibTeX bibliography manager for parsing and querying citation data."""
69
+
70
+ def __init__(self, path: str) -> None:
71
+ """Initialize the bibliography manager.
72
+
73
+ Args:
74
+ path: Path to BibTeX (.bib) file to load
75
+
76
+ Raises:
77
+ RuntimeError: If file cannot be read or parsed
78
+ """
79
+
80
+ def get_cite_key(self, title: str) -> Optional[str]:
81
+ """Find citation key by exact title match.
82
+
83
+ Args:
84
+ title: Full title to search for (case-insensitive)
85
+
86
+ Returns:
87
+ Citation key if exact match found, None otherwise
88
+ """
89
+
90
+ def get_cite_key_fuzzy(self, query: str) -> Optional[str]:
91
+ """Find best matching citation using fuzzy text search.
92
+
93
+ Args:
94
+ query: Search term to find in bibliography entries
95
+
96
+ Returns:
97
+ Citation key of best matching entry, or None if no good match
98
+
99
+ Notes:
100
+ Uses nucleo_matcher for high-quality fuzzy text searching
101
+ See: https://crates.io/crates/nucleo-matcher
102
+ """
@@ -1,3 +1,5 @@
1
+ """Some necessary instances."""
2
+
1
3
  from fabricatio._rust import TemplateManager
2
4
  from fabricatio.config import configs
3
5
 
@@ -15,7 +15,7 @@ class Propose[M: ProposedAble](LLMUsage):
15
15
  self,
16
16
  cls: Type[M],
17
17
  prompt: List[str],
18
- **kwargs: Unpack[GenerateKwargs],
18
+ **kwargs: Unpack[GenerateKwargs[M]],
19
19
  ) -> List[M]: ...
20
20
 
21
21
  @overload
@@ -23,14 +23,14 @@ class Propose[M: ProposedAble](LLMUsage):
23
23
  self,
24
24
  cls: Type[M],
25
25
  prompt: str,
26
- **kwargs: Unpack[GenerateKwargs],
26
+ **kwargs: Unpack[GenerateKwargs[M]],
27
27
  ) -> M: ...
28
28
 
29
29
  async def propose(
30
30
  self,
31
31
  cls: Type[M],
32
32
  prompt: List[str] | str,
33
- **kwargs: Unpack[GenerateKwargs],
33
+ **kwargs: Unpack[GenerateKwargs[M]],
34
34
  ) -> List[M] | M:
35
35
  """Asynchronously proposes a task based on a given prompt and parameters.
36
36
 
@@ -2,9 +2,9 @@
2
2
 
3
3
  from asyncio import gather
4
4
  from itertools import permutations
5
+ from random import sample
5
6
  from typing import Dict, List, Set, Tuple, Union, Unpack, overload
6
7
 
7
- from cache import AsyncLRU
8
8
  from fabricatio._rust_instances import template_manager
9
9
  from fabricatio.config import configs
10
10
  from fabricatio.journal import logger
@@ -17,7 +17,11 @@ from pydantic import NonNegativeInt, PositiveInt
17
17
 
18
18
 
19
19
  class GiveRating(WithBriefing, LLMUsage):
20
- """A class that provides functionality to rate tasks based on a rating manual and score range."""
20
+ """A class that provides functionality to rate tasks based on a rating manual and score range.
21
+
22
+ References:
23
+ Lu X, Li J, Takeuchi K, et al. AHP-powered LLM reasoning for multi-criteria evaluation of open-ended responses[A/OL]. arXiv, 2024. DOI: 10.48550/arXiv.2410.01246.
24
+ """
21
25
 
22
26
  async def rate_fine_grind(
23
27
  self,
@@ -113,7 +117,6 @@ class GiveRating(WithBriefing, LLMUsage):
113
117
  return await gather(*[self.rate_fine_grind(item, manual, score_range, **kwargs) for item in to_rate])
114
118
  raise ValueError("to_rate must be a string or a list of strings")
115
119
 
116
- @AsyncLRU(maxsize=32)
117
120
  async def draft_rating_manual(
118
121
  self, topic: str, criteria: Set[str], **kwargs: Unpack[ValidateKwargs]
119
122
  ) -> Dict[str, str]:
@@ -189,6 +192,7 @@ class GiveRating(WithBriefing, LLMUsage):
189
192
  self,
190
193
  topic: str,
191
194
  examples: List[str],
195
+ m: NonNegativeInt = 0,
192
196
  reasons_count: PositiveInt = 2,
193
197
  criteria_count: PositiveInt = 5,
194
198
  **kwargs: Unpack[ValidateKwargs],
@@ -201,13 +205,21 @@ class GiveRating(WithBriefing, LLMUsage):
201
205
  Parameters:
202
206
  topic (str): The subject topic for the rating criteria.
203
207
  examples (List[str]): A list of example texts to analyze.
208
+ m (NonNegativeInt, optional): The number of examples to sample from the provided list. Defaults to 0 (no sampling).
204
209
  reasons_count (PositiveInt, optional): The number of reasons to extract from each pair of examples. Defaults to 2.
205
210
  criteria_count (PositiveInt, optional): The final number of rating criteria to draft. Defaults to 5.
206
211
  **kwargs (Unpack[ValidateKwargs]): Additional keyword arguments for validation.
207
212
 
208
213
  Returns:
209
214
  Set[str]: A set of drafted rating criteria.
215
+
216
+ Warnings:
217
+ Since this function uses pairwise comparisons, it may not be suitable for large lists of examples.
218
+ For that reason, consider using a smaller list of examples or setting `m` to a non-zero value smaller than the length of the examples.
210
219
  """
220
+ if m:
221
+ examples = sample(examples, m)
222
+
211
223
  kwargs = GenerateKwargs(system_message=f"# your personal briefing: \n{self.briefing}", **kwargs)
212
224
  # extract reasons from the comparison of ordered pairs of extracted from examples
213
225
  reasons = flatten(
@@ -0,0 +1,242 @@
1
+ """A module that provides functionality to rate tasks based on a rating manual and score range."""
2
+
3
+ from typing import List, Optional, Self, Set, Unpack
4
+
5
+ from fabricatio import template_manager
6
+ from fabricatio.capabilities.propose import Propose
7
+ from fabricatio.capabilities.rating import GiveRating
8
+ from fabricatio.config import configs
9
+ from fabricatio.models.generic import Base, Display, ProposedAble, WithBriefing
10
+ from fabricatio.models.kwargs_types import GenerateKwargs, ReviewKwargs
11
+ from fabricatio.models.task import Task
12
+ from pydantic import PrivateAttr
13
+ from questionary import Choice, checkbox
14
+ from rich import print
15
+
16
+
17
+ class ProblemSolutions(Base):
18
+ """Represents a problem-solution pair identified during a review process.
19
+
20
+ This class encapsulates a single problem with its corresponding potential solutions,
21
+ providing a structured way to manage review findings.
22
+
23
+ Attributes:
24
+ problem (str): The problem statement identified during review.
25
+ solutions (List[str]): A collection of potential solutions to address the problem.
26
+ """
27
+
28
+ problem: str
29
+ """The problem identified in the review."""
30
+ solutions: List[str]
31
+ """A collection of potential solutions to address the problem."""
32
+
33
+ def update_problem(self, problem: str) -> Self:
34
+ """Update the problem description.
35
+
36
+ Args:
37
+ problem (str): The new problem description to replace the current one.
38
+
39
+ Returns:
40
+ Self: The current instance with updated problem description.
41
+ """
42
+ self.problem = problem
43
+ return self
44
+
45
+ def update_solutions(self, solutions: List[str]) -> Self:
46
+ """Update the list of potential solutions.
47
+
48
+ Args:
49
+ solutions (List[str]): The new collection of solutions to replace the current ones.
50
+
51
+ Returns:
52
+ Self: The current instance with updated solutions.
53
+ """
54
+ self.solutions = solutions
55
+ return self
56
+
57
+
58
+ class ReviewResult[T](ProposedAble, Display):
59
+ """Represents the outcome of a review process with identified problems and solutions.
60
+
61
+ This class maintains a structured collection of problems found during a review,
62
+ their proposed solutions, and a reference to the original reviewed object.
63
+
64
+ Attributes:
65
+ review_topic (str): The subject or focus area of the review.
66
+ problem_solutions (List[ProblemSolutions]): Collection of problems identified
67
+ during review along with their potential solutions.
68
+
69
+ Type Parameters:
70
+ T: The type of the object being reviewed.
71
+ """
72
+
73
+ review_topic: str
74
+ """The subject or focus area of the review."""
75
+
76
+ problem_solutions: List[ProblemSolutions]
77
+ """Collection of problems identified during review along with their potential solutions."""
78
+
79
+ _ref: T = PrivateAttr(None)
80
+ """Reference to the original object that was reviewed."""
81
+
82
+ def update_topic(self, topic: str) -> Self:
83
+ """Update the review topic.
84
+
85
+ Args:
86
+ topic (str): The new topic to be associated with this review.
87
+
88
+ Returns:
89
+ Self: The current instance with updated review topic.
90
+ """
91
+ self.review_topic = topic
92
+ return self
93
+
94
+ def update_ref[K](self, ref: K) -> "ReviewResult[K]":
95
+ """Update the reference to the reviewed object.
96
+
97
+ Args:
98
+ ref (K): The new reference object to be associated with this review.
99
+
100
+ Returns:
101
+ ReviewResult[K]: The current instance with updated reference type.
102
+ """
103
+ self._ref = ref
104
+ return self
105
+
106
+ def deref(self) -> T:
107
+ """Retrieve the referenced object that was reviewed.
108
+
109
+ Returns:
110
+ T: The original object that was reviewed.
111
+ """
112
+ return self._ref
113
+
114
+ async def supervisor_check(self, check_solutions: bool = False) -> Self:
115
+ """Perform an interactive review session to filter problems and solutions.
116
+
117
+ Presents an interactive prompt allowing a supervisor to select which
118
+ problems (and optionally solutions) should be retained in the final review.
119
+
120
+ Args:
121
+ check_solutions (bool, optional): When True, also prompts for filtering
122
+ individual solutions for each retained problem. Defaults to False.
123
+
124
+ Returns:
125
+ Self: The current instance with filtered problems and solutions.
126
+ """
127
+ if isinstance(self._ref, str):
128
+ display = self._ref
129
+ elif isinstance(self._ref, WithBriefing):
130
+ display = self._ref.briefing
131
+ elif isinstance(self._ref, Display):
132
+ display = self._ref.display()
133
+ else:
134
+ raise TypeError(f"Unsupported type for review: {type(self._ref)}")
135
+ # Choose the problems to retain
136
+ print(display)
137
+ chosen_ones: List[ProblemSolutions] = await checkbox(
138
+ f"Please choose the problems you want to retain.(Default: retain all)\n\t`{self.review_topic}`",
139
+ choices=[Choice(p.problem, p, checked=True) for p in self.problem_solutions],
140
+ ).ask_async()
141
+ if not check_solutions:
142
+ self.problem_solutions = chosen_ones
143
+ return self
144
+
145
+ # Choose the solutions to retain
146
+ for to_exam in chosen_ones:
147
+ to_exam.update_solutions(
148
+ await checkbox(
149
+ f"Please choose the solutions you want to retain.(Default: retain all)\n\t`{to_exam.problem}`",
150
+ choices=[Choice(s, s, checked=True) for s in to_exam.solutions],
151
+ ).ask_async()
152
+ )
153
+ return self
154
+
155
+
156
+ class Review(GiveRating, Propose):
157
+ """Class that provides functionality to review tasks and strings using a language model.
158
+
159
+ This class extends GiveRating and Propose capabilities to analyze content,
160
+ identify problems, and suggest solutions based on specified criteria.
161
+
162
+ The review process can be applied to Task objects or plain strings with
163
+ appropriate topic and criteria.
164
+ """
165
+
166
+ async def review_task[T](self, task: Task[T], **kwargs: Unpack[ReviewKwargs]) -> ReviewResult[Task[T]]:
167
+ """Review a task using specified review criteria.
168
+
169
+ This method analyzes a task object to identify problems and propose solutions
170
+ based on the criteria provided in kwargs.
171
+
172
+ Args:
173
+ task (Task[T]): The task object to be reviewed.
174
+ **kwargs (Unpack[ReviewKwargs]): Additional keyword arguments for the review process,
175
+ including topic and optional criteria.
176
+
177
+ Returns:
178
+ ReviewResult[Task[T]]: A review result containing identified problems and proposed solutions,
179
+ with a reference to the original task.
180
+ """
181
+ return await self.review_obj(task, **kwargs)
182
+
183
+ async def review_string(
184
+ self,
185
+ text: str,
186
+ topic: str,
187
+ criteria: Optional[Set[str]] = None,
188
+ **kwargs: Unpack[GenerateKwargs[ReviewResult[str]]],
189
+ ) -> ReviewResult[str]:
190
+ """Review a string based on specified topic and criteria.
191
+
192
+ This method analyzes a text string to identify problems and propose solutions
193
+ based on the given topic and criteria.
194
+
195
+ Args:
196
+ text (str): The text content to be reviewed.
197
+ topic (str): The subject topic for the review criteria.
198
+ criteria (Optional[Set[str]], optional): A set of criteria for the review.
199
+ If not provided, criteria will be drafted automatically. Defaults to None.
200
+ **kwargs (Unpack[GenerateKwargs]): Additional keyword arguments for the LLM usage.
201
+
202
+ Returns:
203
+ ReviewResult[str]: A review result containing identified problems and proposed solutions,
204
+ with a reference to the original text.
205
+ """
206
+ criteria = criteria or (await self.draft_rating_criteria(topic))
207
+ manual = await self.draft_rating_manual(topic, criteria)
208
+ res: ReviewResult[str] = await self.propose(
209
+ ReviewResult,
210
+ template_manager.render_template(
211
+ configs.templates.review_string_template, {"text": text, "topic": topic, "criteria_manual": manual}
212
+ ),
213
+ **kwargs,
214
+ )
215
+ return res.update_ref(text).update_topic(topic)
216
+
217
+ async def review_obj[M: (Display, WithBriefing)](self, obj: M, **kwargs: Unpack[ReviewKwargs]) -> ReviewResult[M]:
218
+ """Review an object that implements Display or WithBriefing interface.
219
+
220
+ This method extracts displayable text from the object and performs a review
221
+ based on the criteria provided in kwargs.
222
+
223
+ Args:
224
+ obj (M): The object to be reviewed, which must implement either Display or WithBriefing.
225
+ **kwargs (Unpack[ReviewKwargs]): Additional keyword arguments for the review process,
226
+ including topic and optional criteria.
227
+
228
+ Raises:
229
+ TypeError: If the object does not implement Display or WithBriefing.
230
+
231
+ Returns:
232
+ ReviewResult[M]: A review result containing identified problems and proposed solutions,
233
+ with a reference to the original object.
234
+ """
235
+ if isinstance(obj, Display):
236
+ text = obj.display()
237
+ elif isinstance(obj, WithBriefing):
238
+ text = obj.briefing
239
+ else:
240
+ raise TypeError(f"Unsupported type for review: {type(obj)}")
241
+
242
+ return (await self.review_string(text, **kwargs)).update_ref(obj)
@@ -3,6 +3,7 @@
3
3
  from typing import List, Literal, Optional
4
4
 
5
5
  from appdirs import user_config_dir
6
+ from litellm.types.caching import LiteLLMCacheType
6
7
  from pydantic import (
7
8
  BaseModel,
8
9
  ConfigDict,
@@ -25,6 +26,8 @@ from pydantic_settings import (
25
26
  TomlConfigSettingsSource,
26
27
  )
27
28
 
29
+ from fabricatio.models.kwargs_types import CacheKwargs
30
+
28
31
  ROAMING_DIR = user_config_dir("fabricatio", "", roaming=True)
29
32
 
30
33
 
@@ -265,6 +268,19 @@ class RagConfig(BaseModel):
265
268
  """The dimensions of the Milvus server."""
266
269
 
267
270
 
271
+ class CacheConfig(BaseModel):
272
+ """cache configuration class, uses litellm as cache backend. more info see https://docs.litellm.ai/docs/caching/all_caches."""
273
+
274
+ model_config = ConfigDict(use_attribute_docstrings=True)
275
+
276
+ type: Optional[LiteLLMCacheType] = None
277
+ """The type of cache to use. If None, the default cache type will be used."""
278
+ params: CacheKwargs = Field(default_factory=CacheKwargs)
279
+ """The parameters for the cache. If type is None, the default parameters will be used."""
280
+ enabled: bool = Field(default=False)
281
+ """Whether to enable cache."""
282
+
283
+
268
284
  class Settings(BaseSettings):
269
285
  """Application settings class.
270
286
 
@@ -314,6 +330,9 @@ class Settings(BaseSettings):
314
330
  rag: RagConfig = Field(default_factory=RagConfig)
315
331
  """RAG Configuration"""
316
332
 
333
+ cache: CacheConfig = Field(default_factory=CacheConfig)
334
+ """Cache Configuration"""
335
+
317
336
  @classmethod
318
337
  def settings_customise_sources(
319
338
  cls,
@@ -7,6 +7,7 @@ from fabricatio.fs.curd import (
7
7
  delete_directory,
8
8
  delete_file,
9
9
  dump_text,
10
+ gather_files,
10
11
  move_file,
11
12
  tree,
12
13
  )
@@ -19,6 +20,7 @@ __all__ = [
19
20
  "delete_directory",
20
21
  "delete_file",
21
22
  "dump_text",
23
+ "gather_files",
22
24
  "magika",
23
25
  "move_file",
24
26
  "safe_json_read",
@@ -134,3 +134,16 @@ def absolute_path(path: str | Path | PathLike) -> str:
134
134
  str: The absolute path of the file or directory.
135
135
  """
136
136
  return Path(path).expanduser().resolve().as_posix()
137
+
138
+
139
+ def gather_files(directory: str | Path | PathLike, extension: str) -> list[str]:
140
+ """Gather all files with a specific extension in a directory.
141
+
142
+ Args:
143
+ directory (str, Path, PathLike): The directory to search in.
144
+ extension (str): The file extension to look for.
145
+
146
+ Returns:
147
+ list[str]: A list of file paths with the specified extension.
148
+ """
149
+ return [file.as_posix() for file in Path(directory).rglob(f"*.{extension}")]
@@ -18,7 +18,6 @@ logger.add(
18
18
  )
19
19
  logger.add(sys.stderr, level=configs.debug.log_level)
20
20
 
21
-
22
21
  if __name__ == "__main__":
23
22
  logger.debug("This is a trace message.")
24
23
  logger.info("This is an information message.")