vulcan-core 1.1.0__py3-none-any.whl → 1.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of vulcan-core might be problematic. Click here for more details.

vulcan_core/ast_utils.py CHANGED
@@ -24,7 +24,7 @@ class ContractError(Exception):
24
24
 
25
25
  class ScopeAccessError(ContractError):
26
26
  """Raised when a callable attempts to access instances not passed as parameters or when decorated functions attempt
27
- a toccess class attributes instead of parameter instance attributes ."""
27
+ to access class attributes instead of parameter instance attributes."""
28
28
 
29
29
 
30
30
  class NotAFactError(ContractError):
vulcan_core/conditions.py CHANGED
@@ -31,7 +31,7 @@ logger = logging.getLogger(__name__)
31
31
  @dataclass(frozen=True, slots=True)
32
32
  class Expression(DeclaresFacts):
33
33
  """
34
- Abstract base class for defining deferred logical expressions. It captures the assosciation of logic with Facts so
34
+ Abstract base class for defining deferred logical expressions. It captures the association of logic with Facts so
35
35
  that upon a Fact update, the logical expression can be selectively evaluated. It also provides a set of logical
36
36
  operators for combining conditions, resulting in a new CompoundCondition.
37
37
  """
@@ -63,7 +63,7 @@ class Expression(DeclaresFacts):
63
63
  @dataclass(frozen=True, slots=True)
64
64
  class Condition(FactHandler[ConditionCallable, bool], Expression):
65
65
  """
66
- A Condition is a container to defer logical epxressions against a supplied Fact. The expression can be inverted
66
+ A Condition is a container to defer logical expressions against a supplied Fact. The expression can be inverted
67
67
  using the `~` operator. Conditions also support the '&', '|', and '^' operators for combinatorial logic.
68
68
 
69
69
  Attributes:
vulcan_core/engine.py CHANGED
@@ -9,6 +9,7 @@ from types import MappingProxyType
9
9
  from typing import TYPE_CHECKING
10
10
  from uuid import UUID, uuid4
11
11
 
12
+ from vulcan_core.ast_utils import NotAFactError
12
13
  from vulcan_core.models import DeclaresFacts, Fact
13
14
 
14
15
  if TYPE_CHECKING: # pragma: no cover - not used at runtime
@@ -104,6 +105,10 @@ class RuleEngine:
104
105
 
105
106
  if isinstance(fact, partial):
106
107
  fact_name = fact.func.__name__
108
+ fact_class = fact.func
109
+ if not issubclass(fact_class, Fact): # type: ignore
110
+ raise NotAFactError(fact_class)
111
+
107
112
  if fact_name in self._facts:
108
113
  self._facts[fact_name] |= fact
109
114
  else:
@@ -113,19 +118,24 @@ class RuleEngine:
113
118
  msg = f"Fact '{fact_name}' is missing and lacks sufficient defaults to create from partial: {fact}"
114
119
  raise InternalStateError(msg) from err
115
120
  else:
121
+ fact_class = type(fact)
122
+ if not issubclass(fact_class, Fact):
123
+ raise NotAFactError(fact_class)
124
+
116
125
  self._facts[type(fact).__name__] = fact
117
126
 
118
- def rule[T: Fact](self, *, name: str | None = None, when: Expression, then: Action, inverse: Action | None = None):
127
+ def rule[T: Fact](self, *, name: str | None = None, when: Expression, then: Action, inverse: Action | None = None) -> None:
119
128
  """
120
129
  Convenience method for adding a rule to the rule engine.
121
130
 
122
131
  Args:
123
- name (Optional[str]): The name of the rule. Defaults to None.
124
- when (Expression): The condition that triggers the rule.
125
- then (Action): The action to be executed when the condition is met.
126
- inverse (Optional[Action]): The action to be executed when the condition is not met. Defaults to None.
132
+ name (Optional[str]): The name of the rule. Defaults to None.
133
+ when (Expression): The condition that triggers the rule.
134
+ then (Action): The action to be executed when the condition is met.
135
+ inverse (Optional[Action]): The action to be executed when the condition is not met. Defaults to None.
127
136
 
128
- Returns: None
137
+ Returns:
138
+ None
129
139
  """
130
140
  rule = Rule(name, when, then, inverse)
131
141
 
vulcan_core/models.py CHANGED
@@ -120,7 +120,7 @@ class FactMetaclass(type):
120
120
 
121
121
  class Fact(ImmutableAttrAsDict, metaclass=FactMetaclass):
122
122
  """
123
- An abstract class that must be used define rule engine fact schemas and instantiate data into working memory. Facts
123
+ An abstract class that must be used to define rule engine fact schemas and instantiate data into working memory. Facts
124
124
  may be combined with partial facts of the same type using the `|` operator. This is useful for Actions that only
125
125
  need to update a portion of working memory.
126
126
 
@@ -133,8 +133,16 @@ class Fact(ImmutableAttrAsDict, metaclass=FactMetaclass):
133
133
  lefthand operand is created with the partial Fact's keywords applied.
134
134
  """
135
135
  if isinstance(other, Fact):
136
+ if type(self) is not type(other):
137
+ msg = f"Union operator disallowed for types {type(self).__name__} and {type(other).__name__}"
138
+ raise TypeError(msg)
139
+
136
140
  return other # type: ignore
137
141
  else:
142
+ if type(self) is not other.func:
143
+ msg = f"Union operator disallowed for types {type(self).__name__} and {other.func}"
144
+ raise TypeError(msg)
145
+
138
146
  new_fact = copy(self)
139
147
  for kw, value in other.keywords.items():
140
148
  object.__setattr__(new_fact, kw, value)
vulcan_core/util.py CHANGED
@@ -11,7 +11,7 @@ from typing import Any, NoReturn
11
11
 
12
12
  @dataclass(frozen=True)
13
13
  class WithContext:
14
- """Applys a context manager as a decorator.
14
+ """Applies a context manager as a decorator.
15
15
 
16
16
  @WithContext(suppress(Exception))
17
17
  def foo():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: vulcan-core
3
- Version: 1.1.0
3
+ Version: 1.1.1
4
4
  Summary: AI-Hybrid Rules Engine for Logical Reasoning.
5
5
  License: Apache-2.0
6
6
  Keywords: rules,logic,reasoning,ai,artificial intelligence,RAG,LLM
@@ -15,7 +15,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
15
  Provides-Extra: openai
16
16
  Requires-Dist: langchain ; extra == "openai"
17
17
  Requires-Dist: langchain-openai ; extra == "openai"
18
- Requires-Dist: pydantic (>=2.10.6,<2.11.0)
18
+ Requires-Dist: pydantic (>=2.11.1,<2.12.0)
19
19
  Project-URL: Documentation, https://latchfield.com/vulcan/docs
20
20
  Project-URL: Homepage, https://latchfield.com/vulcan
21
21
  Project-URL: Repository, https://github.com/latchfield/vulcan_core
@@ -26,7 +26,7 @@ Description-Content-Type: text/markdown
26
26
  <img alt="Vulcan Logo" src="https://latchfield.com/vulcan/assets/images/vulcan-logo.svg" height="100px">
27
27
 
28
28
  # AI-Hybrid Rules Engine for Logical Reasoning
29
- ![Version](https://img.shields.io/pypi/v/vulcan_core)
29
+ [![Version](https://img.shields.io/pypi/v/vulcan_core)](https://pypi.org/project/vulcan-core/)
30
30
 
31
31
  Vulcan is an AI-hybrid rules engine designed for advanced automated reasoning. It combines the power of rule-based decision systems with LLMs (Large Language Models) for improved consistency and explainability in AI-powered systems.
32
32
 
@@ -59,14 +59,14 @@ Into repeatable, consistent, and explainable rules:
59
59
  ```python
60
60
  # Use natural language for prediction and data retrieval:
61
61
  engine.rule(
62
- when(f"Are {Apple.kind} considered good for baking?"),
63
- then(Apple(baking=True)),
62
+ when=condition(f"Are {Apple.kind} considered good for baking?"),
63
+ then=action(Apple(baking=True)),
64
64
  )
65
65
 
66
66
  # Use computed logic for operations that must be correct:
67
67
  engine.rule(
68
- when(Apple.baking && lambda: Inventory.apples < 10),
69
- then(Order(apples=10)),
68
+ when=condition(Apple.baking && lambda: Inventory.apples < 10),
69
+ then=action(Order(apples=10)),
70
70
  )
71
71
 
72
72
  # Intelligent on-demand rule evaluation:
@@ -0,0 +1,12 @@
1
+ vulcan_core/__init__.py,sha256=pjCnmbMjrsp672WXRQeOV0aSKUEoA_mj0o7q_ouMWs8,1057
2
+ vulcan_core/actions.py,sha256=RO5w5X-drxtDY_mVv0xR2njasWkGPt1AZo9RXsBi8X0,917
3
+ vulcan_core/ast_utils.py,sha256=IeAqk3XPg9Ae-N2nkNxORPVs3b4vv_dtHiSEbYkD9N8,12575
4
+ vulcan_core/conditions.py,sha256=cNwp1M9nprda7i76Anhet4lih_6fTKlUyDYRYPmRKmk,13197
5
+ vulcan_core/engine.py,sha256=WjayTDEjKaIEVkkSZyDjdbu1Xy1XIvPewI83l6Sjo9g,9672
6
+ vulcan_core/models.py,sha256=7um3u-rAy9gg2otTnZFGlKfHJKfsvGEosU3mGq_0jyg,8964
7
+ vulcan_core/util.py,sha256=Uq5uWhrfWd8fNv6IeeTFZRGeLBAECPZUx63UjbbSMrA,3420
8
+ vulcan_core-1.1.1.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
9
+ vulcan_core-1.1.1.dist-info/METADATA,sha256=rDTr3JMTjIGOK1MO9u0oEFyUfsExB4QouvOXwAgd6z4,4424
10
+ vulcan_core-1.1.1.dist-info/NOTICE,sha256=UN1_Gd_Snmu8T62mxExNUdIF2o7DMdGu8bI8rKqhVnc,244
11
+ vulcan_core-1.1.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
12
+ vulcan_core-1.1.1.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- vulcan_core/__init__.py,sha256=pjCnmbMjrsp672WXRQeOV0aSKUEoA_mj0o7q_ouMWs8,1057
2
- vulcan_core/actions.py,sha256=RO5w5X-drxtDY_mVv0xR2njasWkGPt1AZo9RXsBi8X0,917
3
- vulcan_core/ast_utils.py,sha256=dIJgiPaozUZ7ggY9_wksSWO0htG1rxaBJzGpWW3CmUU,12576
4
- vulcan_core/conditions.py,sha256=znFG9eaIib_iA36kOQJFXySisjgexbNqGUYAw3419c0,13198
5
- vulcan_core/engine.py,sha256=UtrfNkrokZazW_l3_zmwKyackJLON-mpGvnNmZyjBqM,9313
6
- vulcan_core/models.py,sha256=gFc5SOE_weoNPZo_kV_R95OYdeOp7L57rKlIwSAwqh4,8584
7
- vulcan_core/util.py,sha256=THlBzIO9zw7JiKGYB8PIan4oRjsGuNaZpx-lgCmUAVI,3419
8
- vulcan_core-1.1.0.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
9
- vulcan_core-1.1.0.dist-info/METADATA,sha256=Hw2a87OIUInw-2wpPdXgXLNtx0Ra3r_82r4qsFFrBaI,4349
10
- vulcan_core-1.1.0.dist-info/NOTICE,sha256=UN1_Gd_Snmu8T62mxExNUdIF2o7DMdGu8bI8rKqhVnc,244
11
- vulcan_core-1.1.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
12
- vulcan_core-1.1.0.dist-info/RECORD,,