vulcan-core 1.1.2__tar.gz → 1.1.3__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.
Potentially problematic release.
This version of vulcan-core might be problematic. Click here for more details.
- {vulcan_core-1.1.2 → vulcan_core-1.1.3}/PKG-INFO +2 -2
- {vulcan_core-1.1.2 → vulcan_core-1.1.3}/README.md +1 -1
- {vulcan_core-1.1.2 → vulcan_core-1.1.3}/pyproject.toml +1 -1
- {vulcan_core-1.1.2 → vulcan_core-1.1.3}/src/vulcan_core/ast_utils.py +23 -15
- {vulcan_core-1.1.2 → vulcan_core-1.1.3}/LICENSE +0 -0
- {vulcan_core-1.1.2 → vulcan_core-1.1.3}/NOTICE +0 -0
- {vulcan_core-1.1.2 → vulcan_core-1.1.3}/src/vulcan_core/__init__.py +0 -0
- {vulcan_core-1.1.2 → vulcan_core-1.1.3}/src/vulcan_core/actions.py +0 -0
- {vulcan_core-1.1.2 → vulcan_core-1.1.3}/src/vulcan_core/conditions.py +0 -0
- {vulcan_core-1.1.2 → vulcan_core-1.1.3}/src/vulcan_core/engine.py +0 -0
- {vulcan_core-1.1.2 → vulcan_core-1.1.3}/src/vulcan_core/models.py +0 -0
- {vulcan_core-1.1.2 → vulcan_core-1.1.3}/src/vulcan_core/util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: vulcan-core
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.3
|
|
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
|
|
@@ -65,7 +65,7 @@ engine.rule(
|
|
|
65
65
|
|
|
66
66
|
# Use computed logic for operations that must be correct:
|
|
67
67
|
engine.rule(
|
|
68
|
-
when=condition(Apple.baking
|
|
68
|
+
when=condition(lambda: Apple.baking and Inventory.apples < 10),
|
|
69
69
|
then=action(Order(apples=10)),
|
|
70
70
|
)
|
|
71
71
|
|
|
@@ -42,7 +42,7 @@ engine.rule(
|
|
|
42
42
|
|
|
43
43
|
# Use computed logic for operations that must be correct:
|
|
44
44
|
engine.rule(
|
|
45
|
-
when=condition(Apple.baking
|
|
45
|
+
when=condition(lambda: Apple.baking and Inventory.apples < 10),
|
|
46
46
|
then=action(Order(apples=10)),
|
|
47
47
|
)
|
|
48
48
|
|
|
@@ -20,7 +20,7 @@ requires = ["poetry-core"]
|
|
|
20
20
|
build-backend = "poetry.core.masonry.api"
|
|
21
21
|
|
|
22
22
|
[tool.poetry]
|
|
23
|
-
version = "1.1.
|
|
23
|
+
version = "1.1.3" # Update manually, or use plugin
|
|
24
24
|
packages = [{ include = "vulcan_core", from="src" }]
|
|
25
25
|
requires-poetry = "~2.1.1"
|
|
26
26
|
classifiers = [
|
|
@@ -5,6 +5,7 @@ import ast
|
|
|
5
5
|
import inspect
|
|
6
6
|
import re
|
|
7
7
|
import textwrap
|
|
8
|
+
import threading
|
|
8
9
|
from ast import Attribute, Module, Name, NodeTransformer, NodeVisitor
|
|
9
10
|
from collections.abc import Callable
|
|
10
11
|
from dataclasses import dataclass, field
|
|
@@ -83,10 +84,11 @@ class AttributeTransformer(NodeTransformer):
|
|
|
83
84
|
return node
|
|
84
85
|
|
|
85
86
|
|
|
86
|
-
# Global index to cache and track lambda
|
|
87
|
+
# Global index to cache and track lambda function positions within the same source lines.
|
|
87
88
|
# Tuple format: (source code, last processed index)
|
|
88
|
-
# TODO:
|
|
89
|
-
#
|
|
89
|
+
# TODO: Consider if a redesign is possible to have a single ASTProcessor handle the entire source line, perhaps eagerly
|
|
90
|
+
# processing all lambdas found in the line before the correspondign `condition` call.
|
|
91
|
+
_lambda_index_lock = threading.Lock()
|
|
90
92
|
lambda_index: dict[Any, tuple[str, int | None]] = {}
|
|
91
93
|
|
|
92
94
|
|
|
@@ -111,21 +113,27 @@ class ASTProcessor[T: Callable]:
|
|
|
111
113
|
try:
|
|
112
114
|
if self.is_lambda:
|
|
113
115
|
# As of Python 3.12, there is no way to determine to which lambda self.func refers in an
|
|
114
|
-
# expression containing multiple lambdas. Therefore we use a global to track the index of each
|
|
116
|
+
# expression containing multiple lambdas. Therefore we use a global dict to track the index of each
|
|
115
117
|
# lambda function encountered, as the order will correspond to the order of ASTProcessor
|
|
116
118
|
# invocations for that line. An additional benefit is that we can also use this as a cache to
|
|
117
119
|
# avoid re-reading the source code for lambda functions sharing the same line.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
index
|
|
128
|
-
|
|
120
|
+
#
|
|
121
|
+
# The key for the index is a hash of the stack trace plus line number, which will be
|
|
122
|
+
# unique for each call of a list of lambdas on the same line.
|
|
123
|
+
frames = inspect.stack()[1:] # Exclude current frame
|
|
124
|
+
key = "".join(f"{f.filename}:{f.lineno}" for f in frames)
|
|
125
|
+
|
|
126
|
+
# Use a lock to ensure thread safety when accessing the global lambda index
|
|
127
|
+
with _lambda_index_lock:
|
|
128
|
+
index = lambda_index.get(key)
|
|
129
|
+
if index is None or index[1] is None:
|
|
130
|
+
self.source = self._get_lambda_source()
|
|
131
|
+
index = (self.source, 0)
|
|
132
|
+
lambda_index[key] = index
|
|
133
|
+
else:
|
|
134
|
+
self.source = index[0]
|
|
135
|
+
index = (self.source, index[1] + 1)
|
|
136
|
+
lambda_index[key] = index
|
|
129
137
|
|
|
130
138
|
# Normalize the lambda source and extract the next lambda expression from the last index
|
|
131
139
|
self.source = self._normalize_lambda_source(self.source, index[1])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|