fabricatio 0.2.5.dev1__tar.gz → 0.2.5.dev2__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 (112) hide show
  1. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/Cargo.lock +17 -0
  2. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/Cargo.toml +1 -0
  3. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/PKG-INFO +1 -2
  4. fabricatio-0.2.5.dev2/examples/reviewer/review.py +27 -0
  5. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/pyproject.toml +1 -2
  6. fabricatio-0.2.5.dev2/python/fabricatio/_rust.pyi +102 -0
  7. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/_rust_instances.py +3 -0
  8. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/capabilities/rating.py +0 -2
  9. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/capabilities/review.py +92 -17
  10. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/config.py +19 -0
  11. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/models/kwargs_types.py +40 -1
  12. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/models/role.py +1 -1
  13. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/models/usages.py +21 -26
  14. fabricatio-0.2.5.dev2/src/bib_tools.rs +73 -0
  15. fabricatio-0.2.5.dev2/src/hbs_helpers.rs +9 -0
  16. fabricatio-0.2.5.dev2/src/templates.rs +104 -0
  17. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/create_json_obj.hbs +16 -2
  18. fabricatio-0.2.5.dev2/templates/built-in/review_string.hbs +22 -0
  19. fabricatio-0.2.5.dev2/templates.tar.gz +0 -0
  20. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/uv.lock +1 -9
  21. fabricatio-0.2.5.dev1/python/fabricatio/_rust.pyi +0 -61
  22. fabricatio-0.2.5.dev1/src/bib_tools.rs +0 -45
  23. fabricatio-0.2.5.dev1/src/hbs_helpers.rs +0 -15
  24. fabricatio-0.2.5.dev1/src/templates.rs +0 -105
  25. fabricatio-0.2.5.dev1/templates/built-in/review_string.hbs +0 -14
  26. fabricatio-0.2.5.dev1/templates.tar.gz +0 -0
  27. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/.github/workflows/build-package.yaml +0 -0
  28. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/.github/workflows/ruff.yaml +0 -0
  29. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/.github/workflows/tests.yaml +0 -0
  30. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/.gitignore +0 -0
  31. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/.python-version +0 -0
  32. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/LICENSE +0 -0
  33. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/Makefile +0 -0
  34. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/README.md +0 -0
  35. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/examples/extract_article/extract.py +0 -0
  36. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/examples/llm_usages/llm_usage.py +0 -0
  37. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/examples/make_a_rating/rating.py +0 -0
  38. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/examples/make_diary/commits.json +0 -0
  39. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/examples/make_diary/diary.py +0 -0
  40. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/examples/minor/hello_fabricatio.py +0 -0
  41. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/examples/propose_task/propose.py +0 -0
  42. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/examples/simple_chat/chat.py +0 -0
  43. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/examples/simple_rag/simple_rag.py +0 -0
  44. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/examples/task_handle/handle_task.py +0 -0
  45. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/examples/write_outline/.gitignore +0 -0
  46. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/examples/write_outline/write_outline.py +0 -0
  47. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/__init__.py +0 -0
  48. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/actions/article.py +0 -0
  49. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/actions/output.py +0 -0
  50. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/actions/rag.py +0 -0
  51. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/capabilities/propose.py +0 -0
  52. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/capabilities/rag.py +0 -0
  53. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/capabilities/task.py +0 -0
  54. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/core.py +0 -0
  55. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/decorators.py +0 -0
  56. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/fs/__init__.py +0 -0
  57. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/fs/curd.py +0 -0
  58. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/fs/readers.py +0 -0
  59. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/journal.py +0 -0
  60. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/models/action.py +0 -0
  61. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/models/events.py +0 -0
  62. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/models/extra.py +0 -0
  63. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/models/generic.py +0 -0
  64. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/models/task.py +0 -0
  65. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/models/tool.py +0 -0
  66. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/models/utils.py +0 -0
  67. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/parser.py +0 -0
  68. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/py.typed +0 -0
  69. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/toolboxes/__init__.py +0 -0
  70. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/toolboxes/arithmetic.py +0 -0
  71. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/toolboxes/fs.py +0 -0
  72. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/workflows/articles.py +0 -0
  73. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/python/fabricatio/workflows/rag.py +0 -0
  74. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/src/hash.rs +0 -0
  75. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/src/lib.rs +0 -0
  76. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/binary-exploitation-ctf-solver.hbs +0 -0
  77. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/claude-xml.hbs +0 -0
  78. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/clean-up-code.hbs +0 -0
  79. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/cryptography-ctf-solver.hbs +0 -0
  80. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/dependencies.hbs +0 -0
  81. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/document-the-code.hbs +0 -0
  82. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/draft_rating_criteria.hbs +0 -0
  83. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/draft_rating_manual.hbs +0 -0
  84. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/draft_rating_weights_klee.hbs +0 -0
  85. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/draft_tool_usage_code.hbs +0 -0
  86. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/extract_criteria_from_reasons.hbs +0 -0
  87. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/extract_reasons_from_examples.hbs +0 -0
  88. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/find-security-vulnerabilities.hbs +0 -0
  89. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/fix-bugs.hbs +0 -0
  90. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/improve-performance.hbs +0 -0
  91. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/liststr.hbs +0 -0
  92. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/make_choice.hbs +0 -0
  93. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/make_judgment.hbs +0 -0
  94. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/pathstr.hbs +0 -0
  95. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/rate_fine_grind.hbs +0 -0
  96. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/refactor.hbs +0 -0
  97. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/refined_query.hbs +0 -0
  98. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/retrieved_display.hbs +0 -0
  99. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/reverse-engineering-ctf-solver.hbs +0 -0
  100. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/task_briefing.hbs +0 -0
  101. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/web-ctf-solver.hbs +0 -0
  102. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/write-git-commit.hbs +0 -0
  103. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/write-github-pull-request.hbs +0 -0
  104. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/templates/built-in/write-github-readme.hbs +0 -0
  105. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/tests/test_config.py +0 -0
  106. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/tests/test_models/test_action.py +0 -0
  107. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/tests/test_models/test_advanced.py +0 -0
  108. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/tests/test_models/test_generic.py +0 -0
  109. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/tests/test_models/test_role.py +0 -0
  110. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/tests/test_models/test_task.py +0 -0
  111. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/tests/test_models/test_tool.py +0 -0
  112. {fabricatio-0.2.5.dev1 → fabricatio-0.2.5.dev2}/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.dev2
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,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-dev2"
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,4 +1,7 @@
1
+ """Some necessary instances."""
2
+
1
3
  from fabricatio._rust import TemplateManager
4
+
2
5
  from fabricatio.config import configs
3
6
 
4
7
  template_manager = TemplateManager(
@@ -4,7 +4,6 @@ from asyncio import gather
4
4
  from itertools import permutations
5
5
  from typing import Dict, List, Set, Tuple, Union, Unpack, overload
6
6
 
7
- from cache import AsyncLRU
8
7
  from fabricatio._rust_instances import template_manager
9
8
  from fabricatio.config import configs
10
9
  from fabricatio.journal import logger
@@ -113,7 +112,6 @@ class GiveRating(WithBriefing, LLMUsage):
113
112
  return await gather(*[self.rate_fine_grind(item, manual, score_range, **kwargs) for item in to_rate])
114
113
  raise ValueError("to_rate must be a string or a list of strings")
115
114
 
116
- @AsyncLRU(maxsize=32)
117
115
  async def draft_rating_manual(
118
116
  self, topic: str, criteria: Set[str], **kwargs: Unpack[ValidateKwargs]
119
117
  ) -> Dict[str, str]:
@@ -1,60 +1,135 @@
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, Set, Unpack
3
+ from typing import List, Optional, Self, Set, Unpack
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
- from fabricatio.models.generic import Display, ProposedAble, WithBriefing
9
+ from fabricatio.models.generic import Base, Display, ProposedAble, WithBriefing
10
10
  from fabricatio.models.kwargs_types import GenerateKwargs, ReviewKwargs
11
11
  from fabricatio.models.task import Task
12
12
  from pydantic import PrivateAttr
13
+ from questionary import Choice, checkbox
14
+
15
+
16
+ class ProblemSolutions(Base):
17
+ """Represents a problem-solution pair identified during a review process.
18
+
19
+ This class encapsulates a single problem with its corresponding potential solutions,
20
+ providing a structured way to manage review findings.
21
+
22
+ Attributes:
23
+ problem (str): The problem statement identified during review.
24
+ solutions (List[str]): A collection of potential solutions to address the problem.
25
+ """
26
+
27
+ problem: str
28
+ """The problem identified in the review."""
29
+ solutions: List[str]
30
+ """A collection of potential solutions to address the problem."""
31
+
32
+ def update_problem(self, problem: str) -> Self:
33
+ """Update the problem description.
34
+
35
+ Args:
36
+ problem (str): The new problem description to replace the current one.
37
+
38
+ Returns:
39
+ Self: The current instance with updated problem description.
40
+ """
41
+ self.problem = problem
42
+ return self
43
+
44
+ def update_solutions(self, solutions: List[str]) -> Self:
45
+ """Update the list of potential solutions.
46
+
47
+ Args:
48
+ solutions (List[str]): The new collection of solutions to replace the current ones.
49
+
50
+ Returns:
51
+ Self: The current instance with updated solutions.
52
+ """
53
+ self.solutions = solutions
54
+ return self
13
55
 
14
56
 
15
57
  class ReviewResult[T](ProposedAble, Display):
16
- """Class that represents the result of a review.
58
+ """Represents the outcome of a review process with identified problems and solutions.
17
59
 
18
- This class holds the problems identified in a review and their proposed solutions,
19
- along with a reference to the reviewed object.
60
+ This class maintains a structured collection of problems found during a review,
61
+ their proposed solutions, and a reference to the original reviewed object.
20
62
 
21
63
  Attributes:
22
- existing_problems (List[str]): List of problems identified in the review.
23
- proposed_solutions (List[str]): List of proposed solutions to the problems identified in the review.
64
+ review_topic (str): The subject or focus area of the review.
65
+ problem_solutions (List[ProblemSolutions]): Collection of problems identified
66
+ during review along with their potential solutions.
24
67
 
25
68
  Type Parameters:
26
69
  T: The type of the object being reviewed.
27
70
  """
28
71
 
29
- existing_problems: List[str]
30
- """List of problems identified in the review."""
72
+ review_topic: str
73
+ """The subject or focus area of the review."""
31
74
 
32
- proposed_solutions: List[str]
33
- """List of proposed solutions to the problems identified in the review."""
75
+ problem_solutions: List[ProblemSolutions]
76
+ """Collection of problems identified during review along with their potential solutions."""
34
77
 
35
78
  _ref: T = PrivateAttr(None)
36
- """Reference to the object being reviewed."""
79
+ """Reference to the original object that was reviewed."""
37
80
 
38
81
  def update_ref[K](self, ref: K) -> "ReviewResult[K]":
39
- """Update the reference to the object being reviewed.
82
+ """Update the reference to the reviewed object.
40
83
 
41
84
  Args:
42
- ref (K): The new reference to the object being reviewed.
85
+ ref (K): The new reference object to be associated with this review.
43
86
 
44
87
  Returns:
45
- ReviewResult[K]: The updated instance of the ReviewResult class with the new reference type.
88
+ ReviewResult[K]: The current instance with updated reference type.
46
89
  """
47
90
  self._ref = ref
48
91
  return self
49
92
 
50
93
  def deref(self) -> T:
51
- """Dereference the object being reviewed.
94
+ """Retrieve the referenced object that was reviewed.
52
95
 
53
96
  Returns:
54
- T: The object being reviewed.
97
+ T: The original object that was reviewed.
55
98
  """
56
99
  return self._ref
57
100
 
101
+ async def supervisor_check(self, check_solutions: bool = False) -> Self:
102
+ """Perform an interactive review session to filter problems and solutions.
103
+
104
+ Presents an interactive prompt allowing a supervisor to select which
105
+ problems (and optionally solutions) should be retained in the final review.
106
+
107
+ Args:
108
+ check_solutions (bool, optional): When True, also prompts for filtering
109
+ individual solutions for each retained problem. Defaults to False.
110
+
111
+ Returns:
112
+ Self: The current instance with filtered problems and solutions.
113
+ """
114
+ # Choose the problems to retain
115
+ chosen_ones: List[ProblemSolutions] = await checkbox(
116
+ f"Please choose the problems you want to retain, under the topic of `{self.review_topic}`.(Default: retain all)",
117
+ choices=[Choice(p.problem, p, checked=True) for p in self.problem_solutions],
118
+ ).ask_async()
119
+ if not check_solutions:
120
+ self.problem_solutions = chosen_ones
121
+ return self
122
+
123
+ # Choose the solutions to retain
124
+ for to_exam in chosen_ones:
125
+ to_exam.update_solutions(
126
+ await checkbox(
127
+ f"Please choose the solutions you want to retain, under the problem of `{to_exam.problem}`.(Default: retain all)",
128
+ choices=[Choice(s, s, checked=True) for s in to_exam.solutions],
129
+ ).ask_async()
130
+ )
131
+ return self
132
+
58
133
 
59
134
  class Review(GiveRating, Propose):
60
135
  """Class that provides functionality to review tasks and strings using a language model.
@@ -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,
@@ -1,7 +1,9 @@
1
1
  """This module contains the types for the keyword arguments of the methods in the models module."""
2
2
 
3
- from typing import List, NotRequired, Set, TypedDict
3
+ from typing import Any, List, NotRequired, Set, TypedDict
4
4
 
5
+ from litellm.caching.caching import CacheMode
6
+ from litellm.types.caching import CachingSupportedCallTypes
5
7
  from pydantic import NonNegativeFloat, NonNegativeInt, PositiveInt
6
8
 
7
9
 
@@ -65,3 +67,40 @@ class ChooseKwargs(GenerateKwargs):
65
67
  """A type representing the keyword arguments for the choose method."""
66
68
 
67
69
  k: NotRequired[NonNegativeInt]
70
+
71
+
72
+ class CacheKwargs(TypedDict, total=False):
73
+ """A type representing the keyword arguments for the cache method."""
74
+
75
+ mode: NotRequired[CacheMode] # when default_on cache is always on, when default_off cache is opt in
76
+ host: NotRequired[str]
77
+ port: NotRequired[str]
78
+ password: NotRequired[str]
79
+ namespace: NotRequired[str]
80
+ ttl: NotRequired[float]
81
+ default_in_memory_ttl: NotRequired[float]
82
+ default_in_redis_ttl: NotRequired[float]
83
+ similarity_threshold: NotRequired[float]
84
+ supported_call_types: NotRequired[List[CachingSupportedCallTypes]]
85
+ # s3 Bucket, boto3 configuration
86
+ s3_bucket_name: NotRequired[str]
87
+ s3_region_name: NotRequired[str]
88
+ s3_api_version: NotRequired[str]
89
+ s3_use_ssl: NotRequired[bool]
90
+ s3_verify: NotRequired[bool | str]
91
+ s3_endpoint_url: NotRequired[str]
92
+ s3_aws_access_key_id: NotRequired[str]
93
+ s3_aws_secret_access_key: NotRequired[str]
94
+ s3_aws_session_token: NotRequired[str]
95
+ s3_config: NotRequired[Any]
96
+ s3_path: NotRequired[str]
97
+ redis_semantic_cache_use_async: bool
98
+ redis_semantic_cache_embedding_model: str
99
+ redis_flush_size: NotRequired[int]
100
+ redis_startup_nodes: NotRequired[List]
101
+ disk_cache_dir: Any
102
+ qdrant_api_base: NotRequired[str]
103
+ qdrant_api_key: NotRequired[str]
104
+ qdrant_collection_name: NotRequired[str]
105
+ qdrant_quantization_config: NotRequired[str]
106
+ qdrant_semantic_cache_embedding_model: str
@@ -15,7 +15,7 @@ from pydantic import Field
15
15
  class Role(ProposeTask, HandleTask, Review):
16
16
  """Class that represents a role with a registry of events and workflows."""
17
17
 
18
- registry: dict[Event | str, WorkFlow] = Field(...)
18
+ registry: dict[Event | str, WorkFlow] = Field(default_factory=dict)
19
19
  """ The registry of events and workflows."""
20
20
 
21
21
  toolboxes: Set[ToolBox] = Field(default_factory=set)
@@ -25,6 +25,14 @@ from litellm.utils import CustomStreamWrapper
25
25
  from more_itertools import duplicates_everseen
26
26
  from pydantic import Field, NonNegativeInt, PositiveInt
27
27
 
28
+ if configs.cache.enabled:
29
+ from litellm.caching import Cache
30
+
31
+ if configs.cache.type is None:
32
+ Cache(**configs.cache.params)
33
+ else:
34
+ Cache(type=configs.cache.type, **configs.cache.params)
35
+
28
36
 
29
37
  class LLMUsage(ScopedConfig):
30
38
  """Class that manages LLM (Large Language Model) usage parameters and methods."""
@@ -105,14 +113,14 @@ class LLMUsage(ScopedConfig):
105
113
  async def aask(
106
114
  self,
107
115
  question: List[str],
108
- system_message: Optional[List[str]] = None,
116
+ system_message: List[str],
109
117
  **kwargs: Unpack[LLMKwargs],
110
118
  ) -> List[str]: ...
111
119
  @overload
112
120
  async def aask(
113
121
  self,
114
122
  question: str,
115
- system_message: Optional[List[str]] = None,
123
+ system_message: List[str],
116
124
  **kwargs: Unpack[LLMKwargs],
117
125
  ) -> List[str]: ...
118
126
  @overload
@@ -148,36 +156,23 @@ class LLMUsage(ScopedConfig):
148
156
  str | List[str]: The content of the model's response message.
149
157
  """
150
158
  system_message = system_message or ""
151
- match (isinstance(question, list), isinstance(system_message, list)):
152
- case (True, True):
159
+ match (question, system_message):
160
+ case (list(q_seq), list(sm_seq)):
153
161
  res = await gather(
154
162
  *[
155
163
  self.ainvoke(n=1, question=q, system_message=sm, **kwargs)
156
- for q, sm in zip(question, system_message, strict=True)
164
+ for q, sm in zip(q_seq, sm_seq, strict=True)
157
165
  ]
158
166
  )
159
167
  return [r.pop().message.content for r in res]
160
- case (True, False):
161
- res = await gather(
162
- *[self.ainvoke(n=1, question=q, system_message=system_message, **kwargs) for q in question]
163
- )
168
+ case (list(q_seq), str(sm)):
169
+ res = await gather(*[self.ainvoke(n=1, question=q, system_message=sm, **kwargs) for q in q_seq])
164
170
  return [r.pop().message.content for r in res]
165
- case (False, True):
166
- res = await gather(
167
- *[self.ainvoke(n=1, question=question, system_message=sm, **kwargs) for sm in system_message]
168
- )
171
+ case (str(q), list(sm_seq)):
172
+ res = await gather(*[self.ainvoke(n=1, question=q, system_message=sm, **kwargs) for sm in sm_seq])
169
173
  return [r.pop().message.content for r in res]
170
- case (False, False):
171
- return (
172
- (
173
- await self.ainvoke(
174
- n=1,
175
- question=question,
176
- system_message=system_message,
177
- **kwargs,
178
- )
179
- ).pop()
180
- ).message.content
174
+ case (str(q), str(sm)):
175
+ return ((await self.ainvoke(n=1, question=q, system_message=sm, **kwargs)).pop()).message.content
181
176
  case _:
182
177
  raise RuntimeError("Should not reach here.")
183
178
 
@@ -514,7 +509,7 @@ class ToolBoxUsage(LLMUsage):
514
509
  logger.warning("No toolboxes available.")
515
510
  return []
516
511
  return await self.achoose(
517
- instruction=task.briefing, # TODO write a template to build a more robust instruction
512
+ instruction=task.briefing,
518
513
  choices=list(self.toolboxes),
519
514
  k=k,
520
515
  max_validations=max_validations,
@@ -548,7 +543,7 @@ class ToolBoxUsage(LLMUsage):
548
543
  logger.warning(f"No tools available in toolbox {toolbox.name}.")
549
544
  return []
550
545
  return await self.achoose(
551
- instruction=task.briefing, # TODO write a template to build a more robust instruction
546
+ instruction=task.briefing,
552
547
  choices=toolbox.tools,
553
548
  k=k,
554
549
  max_validations=max_validations,
@@ -0,0 +1,73 @@
1
+ use biblatex::{Bibliography, ChunksExt};
2
+ use nucleo_matcher::pattern::{AtomKind, CaseMatching, Normalization, Pattern};
3
+ use nucleo_matcher::{Config, Matcher, Utf32Str};
4
+ use pyo3::exceptions::PyRuntimeError;
5
+ use pyo3::prelude::*;
6
+ use rayon::prelude::*;
7
+
8
+ #[pyclass]
9
+ pub struct BibManager {
10
+ source:Bibliography,
11
+ }
12
+
13
+
14
+ #[pymethods]
15
+ impl BibManager {
16
+ /// Create a new BibManager instance.
17
+ #[new]
18
+ fn new(path: String) -> PyResult<Self> {
19
+ let bib = std::fs::read_to_string(path)
20
+ .map_err(|e| PyErr::new::<PyRuntimeError, _>(e.to_string()))?;
21
+
22
+ let source = Bibliography::parse(&bib)
23
+ .map_err(|e| PyErr::new::<PyRuntimeError, _>(e.to_string()))?;
24
+
25
+ Ok(BibManager { source })
26
+ }
27
+
28
+ /// find the cite key of an article with given title
29
+ fn get_cite_key(&self, title: String) -> Option<String> {
30
+ let title_lower = title.to_lowercase();
31
+
32
+ self.source.iter().par_bridge()
33
+ .find_map_any(|entry| {
34
+ let entry_title = entry.title()
35
+ .map_err(|e| PyErr::new::<PyRuntimeError, _>(format!("{}", e)))
36
+ .ok()?
37
+ .to_biblatex_string(false)
38
+ .to_lowercase();
39
+
40
+ (entry_title == title_lower).then(|| entry.key.clone())
41
+ })
42
+ }
43
+
44
+ /// Find the corresponding cite key of an article with given query string using fuzzy matcher
45
+ fn get_cite_key_fuzzy(&self, query: String) -> Option<String> {
46
+ let mut matcher = Matcher::new(Config::DEFAULT);
47
+ let pattern = Pattern::new(
48
+ query.as_str(),
49
+ CaseMatching::Ignore,
50
+ Normalization::Smart,
51
+ AtomKind::Substring,
52
+ );
53
+
54
+ self.source.iter()
55
+ .map(|entry| {
56
+ let mut buf = vec![];
57
+ let text = entry.to_biblatex_string();
58
+ (pattern.score(Utf32Str::new(text.as_str(), &mut buf), &mut matcher), entry)
59
+ })
60
+ .par_bridge()
61
+ // Use filter_map's more concise form with pattern matching
62
+ .filter_map(|(maybe_score, entry)| maybe_score.map(|score| (score, entry)))
63
+ .max_by_key(|(score, _)| *score)
64
+ .map(|(_, entry)| entry.key.clone())
65
+ }
66
+
67
+ }
68
+
69
+
70
+ pub(crate) fn register(_: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
71
+ m.add_class::<BibManager>()?;
72
+ Ok(())
73
+ }
@@ -0,0 +1,9 @@
1
+ use handlebars::handlebars_helper;
2
+ use serde_json::Value;
3
+
4
+ handlebars_helper!(len: |v: Value| match v {
5
+ Value::Array(arr) => arr.len(),
6
+ Value::Object(obj) => obj.len(),
7
+ Value::String(s) => s.len(),
8
+ _ => 0
9
+ });