kailash 0.9.7__py3-none-any.whl → 0.9.9__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.
- kailash/__init__.py +1 -1
- kailash/nodes/ai/iterative_llm_agent.py +19 -38
- kailash/nodes/base.py +58 -5
- {kailash-0.9.7.dist-info → kailash-0.9.9.dist-info}/METADATA +1 -1
- {kailash-0.9.7.dist-info → kailash-0.9.9.dist-info}/RECORD +9 -9
- {kailash-0.9.7.dist-info → kailash-0.9.9.dist-info}/WHEEL +0 -0
- {kailash-0.9.7.dist-info → kailash-0.9.9.dist-info}/entry_points.txt +0 -0
- {kailash-0.9.7.dist-info → kailash-0.9.9.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.9.7.dist-info → kailash-0.9.9.dist-info}/top_level.txt +0 -0
kailash/__init__.py
CHANGED
@@ -94,41 +94,37 @@ class IterativeLLMAgentNode(LLMAgentNode):
|
|
94
94
|
Key Features:
|
95
95
|
- Progressive MCP discovery without pre-configuration
|
96
96
|
- 6-phase iterative process (Discovery → Planning → Execution → Reflection → Convergence → Synthesis)
|
97
|
-
-
|
97
|
+
- Real MCP tool execution with fallback to LLM capabilities
|
98
98
|
- Semantic tool understanding and capability mapping
|
99
99
|
- Adaptive strategy based on iteration results
|
100
100
|
- Smart convergence criteria and resource management
|
101
|
-
- Configurable execution modes (real MCP vs mock for testing)
|
102
101
|
|
103
102
|
Examples:
|
104
|
-
>>> # Basic iterative agent
|
103
|
+
>>> # Basic iterative agent execution
|
105
104
|
>>> agent = IterativeLLMAgentNode()
|
106
105
|
>>> result = agent.execute(
|
107
106
|
... messages=[{"role": "user", "content": "Find and analyze healthcare AI trends"}],
|
108
107
|
... mcp_servers=["http://localhost:8080"],
|
109
|
-
... max_iterations=3
|
110
|
-
... use_real_mcp=True # Enables real MCP tool execution
|
108
|
+
... max_iterations=3
|
111
109
|
... )
|
112
110
|
|
113
|
-
>>> # Advanced iterative agent with custom convergence
|
111
|
+
>>> # Advanced iterative agent with custom convergence
|
114
112
|
>>> result = agent.execute(
|
115
113
|
... messages=[{"role": "user", "content": "Research and recommend AI implementation strategy"}],
|
116
114
|
... mcp_servers=["http://ai-registry:8080", "http://knowledge-base:8081"],
|
117
115
|
... max_iterations=5,
|
118
116
|
... discovery_mode="semantic",
|
119
|
-
... use_real_mcp=True, # Use real MCP tools
|
120
117
|
... convergence_criteria={
|
121
118
|
... "goal_satisfaction": {"threshold": 0.9},
|
122
119
|
... "diminishing_returns": {"min_improvement": 0.1}
|
123
120
|
... }
|
124
121
|
... )
|
125
122
|
|
126
|
-
>>> #
|
123
|
+
>>> # Simple execution example
|
127
124
|
>>> result = agent.execute(
|
128
125
|
... messages=[{"role": "user", "content": "Test query"}],
|
129
126
|
... mcp_servers=["http://localhost:8080"],
|
130
|
-
... max_iterations=2
|
131
|
-
... use_real_mcp=False # Uses mock execution for testing
|
127
|
+
... max_iterations=2
|
132
128
|
... )
|
133
129
|
"""
|
134
130
|
|
@@ -232,18 +228,16 @@ class IterativeLLMAgentNode(LLMAgentNode):
|
|
232
228
|
default=300,
|
233
229
|
description="Timeout for each iteration in seconds",
|
234
230
|
),
|
235
|
-
# MCP Execution Control
|
236
|
-
"use_real_mcp": NodeParameter(
|
237
|
-
name="use_real_mcp",
|
238
|
-
type=bool,
|
239
|
-
required=False,
|
240
|
-
default=True,
|
241
|
-
description="Use real MCP tool execution instead of mock execution",
|
242
|
-
),
|
243
231
|
}
|
244
232
|
|
245
233
|
# Merge base parameters with iterative parameters
|
246
234
|
base_params.update(iterative_params)
|
235
|
+
|
236
|
+
# Remove deprecated mock-related parameters since this node always uses real execution
|
237
|
+
deprecated_params = ["use_real_mcp", "mock_mode"]
|
238
|
+
for param_name in deprecated_params:
|
239
|
+
base_params.pop(param_name, None)
|
240
|
+
|
247
241
|
return base_params
|
248
242
|
|
249
243
|
def run(self, **kwargs) -> dict[str, Any]:
|
@@ -582,7 +576,7 @@ class IterativeLLMAgentNode(LLMAgentNode):
|
|
582
576
|
self, server_config: Any, budget: dict[str, Any]
|
583
577
|
) -> list[dict[str, Any]]:
|
584
578
|
"""Discover resources from a specific MCP server."""
|
585
|
-
#
|
579
|
+
# Default implementation - provides basic resource discovery
|
586
580
|
try:
|
587
581
|
server_id = (
|
588
582
|
server_config
|
@@ -591,8 +585,8 @@ class IterativeLLMAgentNode(LLMAgentNode):
|
|
591
585
|
)
|
592
586
|
max_resources = budget.get("max_resources", 50)
|
593
587
|
|
594
|
-
#
|
595
|
-
|
588
|
+
# Default discovered resources
|
589
|
+
default_resources = [
|
596
590
|
{
|
597
591
|
"uri": f"{server_id}/resource/data/overview",
|
598
592
|
"name": "Data Overview",
|
@@ -607,7 +601,7 @@ class IterativeLLMAgentNode(LLMAgentNode):
|
|
607
601
|
},
|
608
602
|
]
|
609
603
|
|
610
|
-
return
|
604
|
+
return default_resources[:max_resources]
|
611
605
|
|
612
606
|
except Exception as e:
|
613
607
|
self.logger.debug(f"Resource discovery failed: {e}")
|
@@ -669,7 +663,7 @@ class IterativeLLMAgentNode(LLMAgentNode):
|
|
669
663
|
domain=domain,
|
670
664
|
complexity=complexity,
|
671
665
|
dependencies=[],
|
672
|
-
confidence=0.8, #
|
666
|
+
confidence=0.8, # Default confidence estimate
|
673
667
|
server_source=server_id,
|
674
668
|
)
|
675
669
|
|
@@ -779,9 +773,6 @@ class IterativeLLMAgentNode(LLMAgentNode):
|
|
779
773
|
"errors": [],
|
780
774
|
}
|
781
775
|
|
782
|
-
# Check if we should use real MCP tool execution
|
783
|
-
use_real_mcp = kwargs.get("use_real_mcp", True)
|
784
|
-
|
785
776
|
# Handle direct LLM response mode
|
786
777
|
if plan.get("planning_mode") == "direct_llm":
|
787
778
|
try:
|
@@ -828,21 +819,11 @@ class IterativeLLMAgentNode(LLMAgentNode):
|
|
828
819
|
tools = step.get("tools", [])
|
829
820
|
|
830
821
|
try:
|
831
|
-
if
|
822
|
+
if tools:
|
832
823
|
# Real MCP tool execution
|
833
824
|
step_result = self._execute_tools_with_mcp(
|
834
825
|
step_num, action, tools, discoveries, kwargs
|
835
826
|
)
|
836
|
-
elif tools:
|
837
|
-
# Mock tool execution for backward compatibility
|
838
|
-
step_result = {
|
839
|
-
"step": step_num,
|
840
|
-
"action": action,
|
841
|
-
"tools_used": tools,
|
842
|
-
"output": f"Mock execution result for {action} using tools: {', '.join(tools)}",
|
843
|
-
"success": True,
|
844
|
-
"duration": 1.5,
|
845
|
-
}
|
846
827
|
else:
|
847
828
|
# No tools available, try direct LLM call for this step
|
848
829
|
self.logger.info(
|
@@ -1814,7 +1795,7 @@ provide your best analysis of the query directly.""",
|
|
1814
1795
|
"total_tools_used": total_tools_used,
|
1815
1796
|
"total_api_calls": total_api_calls,
|
1816
1797
|
"average_iteration_time": total_duration / max(len(iterations), 1),
|
1817
|
-
"estimated_cost_usd": total_api_calls * 0.01, #
|
1798
|
+
"estimated_cost_usd": total_api_calls * 0.01, # Simple cost estimation
|
1818
1799
|
}
|
1819
1800
|
|
1820
1801
|
def _phase_convergence_with_mode(
|
kailash/nodes/base.py
CHANGED
@@ -216,17 +216,58 @@ class Node(ABC):
|
|
216
216
|
)
|
217
217
|
self.logger = logging.getLogger(f"kailash.nodes.{self.id}")
|
218
218
|
|
219
|
-
# Filter out internal fields from config
|
220
|
-
|
219
|
+
# Filter out internal fields from config with comprehensive parameter handling
|
220
|
+
# Get parameter definitions once and cache for both filtering and validation
|
221
|
+
try:
|
222
|
+
if not hasattr(self, "_temp_param_definitions"):
|
223
|
+
self._temp_param_definitions = self.get_parameters()
|
224
|
+
defined_params = set(self._temp_param_definitions.keys())
|
225
|
+
except Exception as e:
|
226
|
+
# If get_parameters() fails, log but continue with safe defaults
|
227
|
+
self.logger.debug(
|
228
|
+
f"Could not get parameter definitions during init: {e}"
|
229
|
+
)
|
230
|
+
defined_params = set()
|
231
|
+
self._temp_param_definitions = {}
|
232
|
+
|
233
|
+
# Comprehensive parameter filtering: handle ALL potential conflicts
|
234
|
+
# Fields that are always internal (never user parameters)
|
235
|
+
always_internal = {"metadata"}
|
236
|
+
|
237
|
+
# Fields that can be either internal or user parameters
|
238
|
+
potentially_user_params = {
|
221
239
|
"id",
|
222
240
|
"name",
|
223
241
|
"description",
|
224
242
|
"version",
|
225
243
|
"author",
|
226
244
|
"tags",
|
227
|
-
"metadata",
|
228
245
|
}
|
229
|
-
|
246
|
+
|
247
|
+
# Build dynamic filter list based on user-defined parameters
|
248
|
+
internal_fields = always_internal.copy()
|
249
|
+
for field in potentially_user_params:
|
250
|
+
if field not in defined_params:
|
251
|
+
# Field is not user-defined, so treat as internal field
|
252
|
+
internal_fields.add(field)
|
253
|
+
# If field IS user-defined, don't add to internal_fields (preserve it)
|
254
|
+
|
255
|
+
# Also filter any field that starts with metadata prefix or other internal patterns
|
256
|
+
# This handles cases like 'metadata_name', 'metadata_*', etc.
|
257
|
+
def is_internal_field(field_name: str) -> bool:
|
258
|
+
# Check if it's in our explicit internal fields list
|
259
|
+
if field_name in internal_fields:
|
260
|
+
return True
|
261
|
+
# Check for metadata-related field patterns
|
262
|
+
if field_name.startswith("metadata_"):
|
263
|
+
return True
|
264
|
+
# Check for other internal patterns
|
265
|
+
if field_name.startswith("_"): # Private fields
|
266
|
+
return True
|
267
|
+
return False
|
268
|
+
|
269
|
+
# Apply comprehensive filtering
|
270
|
+
self.config = {k: v for k, v in kwargs.items() if not is_internal_field(k)}
|
230
271
|
|
231
272
|
# Parameter resolution cache - initialize before validation
|
232
273
|
cache_size = int(
|
@@ -554,11 +595,23 @@ class Node(ABC):
|
|
554
595
|
return bool(re.match(r"^\$\{[^}]+\}$", value))
|
555
596
|
|
556
597
|
def _get_cached_parameters(self) -> dict[str, NodeParameter]:
|
557
|
-
"""Get cached parameter definitions.
|
598
|
+
"""Get cached parameter definitions with optimal performance.
|
599
|
+
|
600
|
+
Uses parameters cached during initialization to avoid duplicate get_parameters() calls.
|
558
601
|
|
559
602
|
Returns:
|
560
603
|
Dictionary of parameter definitions, cached for performance
|
561
604
|
"""
|
605
|
+
# First check if we have parameters cached from initialization
|
606
|
+
if hasattr(self, "_temp_param_definitions") and self._temp_param_definitions:
|
607
|
+
# Use cached parameters from init and clean up temporary cache
|
608
|
+
if self._cached_params is None:
|
609
|
+
self._cached_params = self._temp_param_definitions
|
610
|
+
# Clean up temporary cache to free memory
|
611
|
+
delattr(self, "_temp_param_definitions")
|
612
|
+
return self._cached_params
|
613
|
+
|
614
|
+
# Fallback to original behavior if no cached parameters from init
|
562
615
|
if self._cached_params is None:
|
563
616
|
try:
|
564
617
|
self._cached_params = self.get_parameters()
|
@@ -1,4 +1,4 @@
|
|
1
|
-
kailash/__init__.py,sha256=
|
1
|
+
kailash/__init__.py,sha256=FUBzXZ35fF3M-aPSgCf_FFdhXfG8KWO_ymwnSP78xgI,2771
|
2
2
|
kailash/__main__.py,sha256=vr7TVE5o16V6LsTmRFKG6RDKUXHpIWYdZ6Dok2HkHnI,198
|
3
3
|
kailash/access_control.py,sha256=MjKtkoQ2sg1Mgfe7ovGxVwhAbpJKvaepPWr8dxOueMA,26058
|
4
4
|
kailash/access_control_abac.py,sha256=FPfa_8PuDP3AxTjdWfiH3ntwWO8NodA0py9W8SE5dno,30263
|
@@ -140,7 +140,7 @@ kailash/monitoring/__init__.py,sha256=C5WmkNpk_mmAScqMWiCfkUbjhM5W16dsnRnc3Ial-U
|
|
140
140
|
kailash/monitoring/alerts.py,sha256=eKX4ooPw1EicumPuswlR_nU18UgRETWvFg8FzCW5pVU,21416
|
141
141
|
kailash/monitoring/metrics.py,sha256=SiAnL3o6K0QaJHgfAuWBa-0pTkW5zymhuPEsj4bgOgM,22022
|
142
142
|
kailash/nodes/__init__.py,sha256=p2KSo0dyUBCLClU123qpQ0tyv5S_36PTxosNyW58nyY,1031
|
143
|
-
kailash/nodes/base.py,sha256=
|
143
|
+
kailash/nodes/base.py,sha256=GR2E1fWf8j1yMvJic7m2NAih7kjY1NtoDi47hHwoZ40,85437
|
144
144
|
kailash/nodes/base_async.py,sha256=whxepCiVplrltfzEQuabmnGCpEV5WgfqwgxbLdCyiDk,8864
|
145
145
|
kailash/nodes/base_cycle_aware.py,sha256=Xpze9xZzLepWeLpi9Y3tMn1dm2LVv-omr5TSQuGTtWo,13377
|
146
146
|
kailash/nodes/base_with_acl.py,sha256=ZfrkLPgrEBcNbG0LKvtq6glDxyOYOMRw3VXX4vWX6bI,11852
|
@@ -166,7 +166,7 @@ kailash/nodes/ai/ai_providers.py,sha256=egfiOZzPmZ10d3wBCJ6ST4tRFrrtq0kt1VyCqxVp
|
|
166
166
|
kailash/nodes/ai/embedding_generator.py,sha256=akGCzz7zLRSziqEQCiPwL2qWhRWxuM_1RQh-YtVEddw,31879
|
167
167
|
kailash/nodes/ai/hybrid_search.py,sha256=k26uDDP_bwrIpv7Yl7PBCPvWSyQEmTlBjI1IpbgDsO4,35446
|
168
168
|
kailash/nodes/ai/intelligent_agent_orchestrator.py,sha256=LvBqMKc64zSxFWVCjbLKKel2QwEzoTeJAEgna7rZw00,83097
|
169
|
-
kailash/nodes/ai/iterative_llm_agent.py,sha256=
|
169
|
+
kailash/nodes/ai/iterative_llm_agent.py,sha256=Q_letP5mHtO225LBX0Tq5GlPkXkk-yWf3oFEOJTP6Z0,100289
|
170
170
|
kailash/nodes/ai/llm_agent.py,sha256=NeNJZbV_VOUbULug2LASwyzLyoUO5wi58Bc9sXTubuc,90181
|
171
171
|
kailash/nodes/ai/models.py,sha256=wsEeUTuegy87mnLtKgSTg7ggCXvC1n3MsL-iZ4qujHs,16393
|
172
172
|
kailash/nodes/ai/self_organizing.py,sha256=B7NwKaBW8OHQBf5b0F9bSs8Wm-5BDJ9IjIkxS9h00mg,62885
|
@@ -403,9 +403,9 @@ kailash/workflow/templates.py,sha256=XQMAKZXC2dlxgMMQhSEOWAF3hIbe9JJt9j_THchhAm8
|
|
403
403
|
kailash/workflow/type_inference.py,sha256=i1F7Yd_Z3elTXrthsLpqGbOnQBIVVVEjhRpI0HrIjd0,24492
|
404
404
|
kailash/workflow/validation.py,sha256=r2zApGiiG8UEn7p5Ji842l8OR1_KftzDkWc7gg0cac0,44675
|
405
405
|
kailash/workflow/visualization.py,sha256=nHBW-Ai8QBMZtn2Nf3EE1_aiMGi9S6Ui_BfpA5KbJPU,23187
|
406
|
-
kailash-0.9.
|
407
|
-
kailash-0.9.
|
408
|
-
kailash-0.9.
|
409
|
-
kailash-0.9.
|
410
|
-
kailash-0.9.
|
411
|
-
kailash-0.9.
|
406
|
+
kailash-0.9.9.dist-info/licenses/LICENSE,sha256=Axe6g7bTrJkToK9h9j2SpRUKKNaDZDCo2lQ2zPxCE6s,1065
|
407
|
+
kailash-0.9.9.dist-info/METADATA,sha256=MR4Ore7NAIr_V4yKTpwxqL4EVyoFMjO2hlYZRReAigQ,22298
|
408
|
+
kailash-0.9.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
409
|
+
kailash-0.9.9.dist-info/entry_points.txt,sha256=M_q3b8PG5W4XbhSgESzIJjh3_4OBKtZFYFsOdkr2vO4,45
|
410
|
+
kailash-0.9.9.dist-info/top_level.txt,sha256=z7GzH2mxl66498pVf5HKwo5wwfPtt9Aq95uZUpH6JV0,8
|
411
|
+
kailash-0.9.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|