kailash 0.9.19__py3-none-any.whl → 0.9.21__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.
@@ -49,11 +49,14 @@ Examples:
49
49
  import ast
50
50
  import importlib.util
51
51
  import inspect
52
+ import json
52
53
  import logging
53
54
  import os
54
55
  import resource
55
56
  import traceback
56
57
  from collections.abc import Callable
58
+ from datetime import date, datetime
59
+ from decimal import Decimal
57
60
  from pathlib import Path
58
61
  from typing import Any, get_type_hints
59
62
 
@@ -617,6 +620,37 @@ class CodeExecutor:
617
620
  logger.error(error_msg)
618
621
  raise NodeExecutionError(error_msg)
619
622
 
623
+ def _ensure_serializable(self, data: Any) -> Any:
624
+ """Ensure data is JSON-serializable following AsyncSQL pattern."""
625
+ if data is None:
626
+ return None
627
+ elif isinstance(data, (str, int, float, bool)):
628
+ return data
629
+ elif isinstance(data, (datetime, date)):
630
+ return data.isoformat()
631
+ elif isinstance(data, Decimal):
632
+ return float(data)
633
+ elif isinstance(data, dict):
634
+ return {k: self._ensure_serializable(v) for k, v in data.items()}
635
+ elif isinstance(data, (list, tuple)):
636
+ return [self._ensure_serializable(item) for item in data]
637
+ else:
638
+ try:
639
+ json.dumps(data)
640
+ return data
641
+ except (TypeError, ValueError):
642
+ # Check if object has .to_dict() method for enhanced validation
643
+ if hasattr(data, "to_dict") and callable(getattr(data, "to_dict")):
644
+ try:
645
+ # Convert object to dict using its to_dict() method
646
+ dict_result = data.to_dict()
647
+ # Recursively ensure the dict result is also serializable
648
+ return self._ensure_json_serializable(dict_result)
649
+ except (TypeError, ValueError, AttributeError):
650
+ # If .to_dict() exists but fails, fall back to string
651
+ return str(data)
652
+ return str(data)
653
+
620
654
 
621
655
  class FunctionWrapper:
622
656
  """Wrapper for converting Python functions to nodes.
@@ -651,6 +685,37 @@ class FunctionWrapper:
651
685
  # Handle cases where type hints can't be resolved
652
686
  self.type_hints = {}
653
687
 
688
+ def _ensure_serializable(self, data: Any) -> Any:
689
+ """Ensure data is JSON-serializable."""
690
+ if data is None:
691
+ return None
692
+ elif isinstance(data, (str, int, float, bool)):
693
+ return data
694
+ elif isinstance(data, (datetime, date)):
695
+ return data.isoformat()
696
+ elif isinstance(data, Decimal):
697
+ return float(data)
698
+ elif isinstance(data, dict):
699
+ return {k: self._ensure_serializable(v) for k, v in data.items()}
700
+ elif isinstance(data, (list, tuple)):
701
+ return [self._ensure_serializable(item) for item in data]
702
+ else:
703
+ try:
704
+ json.dumps(data)
705
+ return data
706
+ except (TypeError, ValueError):
707
+ # Check if object has .to_dict() method for enhanced validation
708
+ if hasattr(data, "to_dict") and callable(getattr(data, "to_dict")):
709
+ try:
710
+ # Convert object to dict using its to_dict() method
711
+ dict_result = data.to_dict()
712
+ # Recursively ensure the dict result is also serializable
713
+ return self._ensure_json_serializable(dict_result)
714
+ except (TypeError, ValueError, AttributeError):
715
+ # If .to_dict() exists but fails, fall back to string
716
+ return str(data)
717
+ return str(data)
718
+
654
719
  def get_input_types(self) -> dict[str, type]:
655
720
  """Extract input types from function signature.
656
721
 
@@ -710,18 +775,51 @@ class FunctionWrapper:
710
775
  return self.type_hints.get("return", Any)
711
776
 
712
777
  def execute(self, inputs: dict[str, Any]) -> dict[str, Any]:
713
- """Execute the wrapped function."""
778
+ """Execute the wrapped function with proper serialization."""
714
779
  result = self.executor.execute_function(self.func, inputs)
715
780
 
716
- # Always wrap results in "result" key for consistent validation
717
- # This ensures both dict and non-dict returns have the same structure
718
- if not isinstance(result, dict):
719
- result = {"result": result}
720
- else:
721
- # For dict results, wrap the entire dict in "result" key
722
- result = {"result": result}
781
+ # Ensure JSON serializability inline
782
+ result = self._ensure_json_serializable(result)
723
783
 
724
- return result
784
+ # Smart wrapping: only wrap if result doesn't already have expected structure
785
+ # If function already returns {"result": value}, don't double-wrap
786
+ if isinstance(result, dict) and len(result) == 1 and "result" in result:
787
+ # Function already returned properly formatted result
788
+ return result
789
+ else:
790
+ # Wrap result for consistent schema validation
791
+ return {"result": result}
792
+
793
+ def _ensure_json_serializable(self, data: Any) -> Any:
794
+ """Convert data to JSON-serializable format."""
795
+ if data is None:
796
+ return None
797
+ elif isinstance(data, (str, int, float, bool)):
798
+ return data
799
+ elif isinstance(data, (datetime, date)):
800
+ return data.isoformat()
801
+ elif isinstance(data, Decimal):
802
+ return float(data)
803
+ elif isinstance(data, dict):
804
+ return {k: self._ensure_json_serializable(v) for k, v in data.items()}
805
+ elif isinstance(data, (list, tuple)):
806
+ return [self._ensure_json_serializable(item) for item in data]
807
+ else:
808
+ try:
809
+ json.dumps(data)
810
+ return data
811
+ except (TypeError, ValueError):
812
+ # Check if object has .to_dict() method for enhanced validation
813
+ if hasattr(data, "to_dict") and callable(getattr(data, "to_dict")):
814
+ try:
815
+ # Convert object to dict using its to_dict() method
816
+ dict_result = data.to_dict()
817
+ # Recursively ensure the dict result is also serializable
818
+ return self._ensure_json_serializable(dict_result)
819
+ except (TypeError, ValueError, AttributeError):
820
+ # If .to_dict() exists but fails, fall back to string
821
+ return str(data)
822
+ return str(data)
725
823
 
726
824
  def to_node(
727
825
  self,
@@ -837,6 +935,37 @@ class ClassWrapper:
837
935
  # Handle descriptor objects like properties
838
936
  self.type_hints = {}
839
937
 
938
+ def _ensure_serializable(self, data: Any) -> Any:
939
+ """Ensure data is JSON-serializable."""
940
+ if data is None:
941
+ return None
942
+ elif isinstance(data, (str, int, float, bool)):
943
+ return data
944
+ elif isinstance(data, (datetime, date)):
945
+ return data.isoformat()
946
+ elif isinstance(data, Decimal):
947
+ return float(data)
948
+ elif isinstance(data, dict):
949
+ return {k: self._ensure_serializable(v) for k, v in data.items()}
950
+ elif isinstance(data, (list, tuple)):
951
+ return [self._ensure_serializable(item) for item in data]
952
+ else:
953
+ try:
954
+ json.dumps(data)
955
+ return data
956
+ except (TypeError, ValueError):
957
+ # Check if object has .to_dict() method for enhanced validation
958
+ if hasattr(data, "to_dict") and callable(getattr(data, "to_dict")):
959
+ try:
960
+ # Convert object to dict using its to_dict() method
961
+ dict_result = data.to_dict()
962
+ # Recursively ensure the dict result is also serializable
963
+ return self._ensure_json_serializable(dict_result)
964
+ except (TypeError, ValueError, AttributeError):
965
+ # If .to_dict() exists but fails, fall back to string
966
+ return str(data)
967
+ return str(data)
968
+
840
969
  def get_input_types(self) -> dict[str, type]:
841
970
  """Extract input types from method signature."""
842
971
  input_types = {}
@@ -900,16 +1029,48 @@ class ClassWrapper:
900
1029
  # Execute the method
901
1030
  result = self.executor.execute_function(method, inputs)
902
1031
 
903
- # Always wrap results in "result" key for consistent validation
904
- # This ensures both dict and non-dict returns have the same structure
1032
+ # Ensure JSON serializability inline
1033
+ result = self._ensure_json_serializable(result)
1034
+
1035
+ # Smart wrapping: only wrap non-dict results in "result" key
1036
+ # Dict results are returned as-is to avoid double wrapping
905
1037
  if not isinstance(result, dict):
906
1038
  result = {"result": result}
907
- else:
908
- # For dict results, wrap the entire dict in "result" key
909
- result = {"result": result}
1039
+ # Dict results are already properly structured, no wrapping needed
910
1040
 
911
1041
  return result
912
1042
 
1043
+ def _ensure_json_serializable(self, data: Any) -> Any:
1044
+ """Convert data to JSON-serializable format."""
1045
+ if data is None:
1046
+ return None
1047
+ elif isinstance(data, (str, int, float, bool)):
1048
+ return data
1049
+ elif isinstance(data, (datetime, date)):
1050
+ return data.isoformat()
1051
+ elif isinstance(data, Decimal):
1052
+ return float(data)
1053
+ elif isinstance(data, dict):
1054
+ return {k: self._ensure_json_serializable(v) for k, v in data.items()}
1055
+ elif isinstance(data, (list, tuple)):
1056
+ return [self._ensure_json_serializable(item) for item in data]
1057
+ else:
1058
+ try:
1059
+ json.dumps(data)
1060
+ return data
1061
+ except (TypeError, ValueError):
1062
+ # Check if object has .to_dict() method for enhanced validation
1063
+ if hasattr(data, "to_dict") and callable(getattr(data, "to_dict")):
1064
+ try:
1065
+ # Convert object to dict using its to_dict() method
1066
+ dict_result = data.to_dict()
1067
+ # Recursively ensure the dict result is also serializable
1068
+ return self._ensure_json_serializable(dict_result)
1069
+ except (TypeError, ValueError, AttributeError):
1070
+ # If .to_dict() exists but fails, fall back to string
1071
+ return str(data)
1072
+ return str(data)
1073
+
913
1074
  def to_node(
914
1075
  self,
915
1076
  name: str | None = None,
@@ -1272,7 +1433,9 @@ class PythonCodeNode(Node):
1272
1433
  elif self.function:
1273
1434
  # Execute function
1274
1435
  wrapper = FunctionWrapper(self.function, self.executor)
1275
- return wrapper.execute(kwargs)
1436
+ result = wrapper.execute(kwargs)
1437
+ # FunctionWrapper.execute() already handles result wrapping
1438
+ return result
1276
1439
 
1277
1440
  elif self.class_type:
1278
1441
  # Execute class method
@@ -3255,8 +3255,17 @@ class AsyncSQLDatabaseNode(AsyncNode):
3255
3255
 
3256
3256
  def _generate_pool_key(self) -> str:
3257
3257
  """Generate a unique key for connection pool sharing."""
3258
- # Create a unique key based on connection parameters
3258
+ # Get event loop ID for isolation
3259
+ try:
3260
+ loop = asyncio.get_running_loop()
3261
+ loop_id = str(id(loop))
3262
+ except RuntimeError:
3263
+ # No running loop (initialization phase)
3264
+ loop_id = "no_loop"
3265
+
3266
+ # Create a unique key based on event loop and connection parameters
3259
3267
  key_parts = [
3268
+ loop_id, # Event loop isolation
3260
3269
  self.config.get("database_type", ""),
3261
3270
  self.config.get("connection_string", "")
3262
3271
  or (
@@ -3295,16 +3304,30 @@ class AsyncSQLDatabaseNode(AsyncNode):
3295
3304
  ):
3296
3305
 
3297
3306
  if self._pool_key in self._shared_pools:
3298
- # Reuse existing pool
3307
+ # Validate pool's event loop is still running before reuse
3299
3308
  adapter, ref_count = self._shared_pools[self._pool_key]
3300
- self._shared_pools[self._pool_key] = (
3301
- adapter,
3302
- ref_count + 1,
3303
- )
3304
- self._adapter = adapter
3305
- self._connected = True
3306
- logger.debug(f"Using class-level shared pool for {self.id}")
3307
- return self._adapter
3309
+
3310
+ try:
3311
+ # Check if we have a running event loop
3312
+ pool_loop = asyncio.get_running_loop()
3313
+ # If we got here, loop is running - safe to reuse
3314
+ self._shared_pools[self._pool_key] = (
3315
+ adapter,
3316
+ ref_count + 1,
3317
+ )
3318
+ self._adapter = adapter
3319
+ self._connected = True
3320
+ logger.debug(
3321
+ f"Using class-level shared pool for {self.id}"
3322
+ )
3323
+ return self._adapter
3324
+ except RuntimeError:
3325
+ # Loop is closed - remove stale pool
3326
+ logger.warning(
3327
+ f"Removing stale pool for {self._pool_key} - event loop closed"
3328
+ )
3329
+ del self._shared_pools[self._pool_key]
3330
+ # Fall through to create new pool
3308
3331
 
3309
3332
  # Create new shared pool
3310
3333
  self._adapter = await self._create_adapter()
@@ -4000,8 +4023,51 @@ class AsyncSQLDatabaseNode(AsyncNode):
4000
4023
 
4001
4024
  metrics["pools"].append(pool_info)
4002
4025
 
4026
+ # Clean up stale pools from closed event loops
4027
+ cleaned_pools = cls._cleanup_closed_loop_pools()
4028
+ if cleaned_pools > 0:
4029
+ metrics["cleaned_stale_pools"] = cleaned_pools
4030
+
4003
4031
  return metrics
4004
4032
 
4033
+ @classmethod
4034
+ def _cleanup_closed_loop_pools(cls) -> int:
4035
+ """
4036
+ Clean up pools from closed event loops.
4037
+
4038
+ Returns:
4039
+ Number of pools removed
4040
+ """
4041
+ removed_count = 0
4042
+ keys_to_remove = []
4043
+
4044
+ for pool_key in list(cls._shared_pools.keys()):
4045
+ # Extract loop ID from pool key (first part before "|")
4046
+ parts = pool_key.split("|")
4047
+ if len(parts) > 0:
4048
+ loop_id_str = parts[0]
4049
+
4050
+ # Check if this pool's event loop is still running
4051
+ try:
4052
+ current_loop = asyncio.get_running_loop()
4053
+ current_loop_id = str(id(current_loop))
4054
+
4055
+ # If loop IDs don't match and pool is stale, mark for removal
4056
+ if loop_id_str != current_loop_id and loop_id_str != "no_loop":
4057
+ keys_to_remove.append(pool_key)
4058
+ except RuntimeError:
4059
+ # No current loop - mark old pools for removal
4060
+ if loop_id_str != "no_loop":
4061
+ keys_to_remove.append(pool_key)
4062
+
4063
+ # Remove stale pools
4064
+ for key in keys_to_remove:
4065
+ if key in cls._shared_pools:
4066
+ del cls._shared_pools[key]
4067
+ removed_count += 1
4068
+
4069
+ return removed_count
4070
+
4005
4071
  @classmethod
4006
4072
  async def clear_shared_pools(cls) -> None:
4007
4073
  """Clear all shared connection pools. Use with caution!"""
@@ -558,7 +558,7 @@ class WorkflowBuilder:
558
558
  Raises:
559
559
  WorkflowValidationError: If node_id is already used or instance is invalid
560
560
  """
561
- return self.add_node(node_instance, node_id)
561
+ return self._add_node_instance(node_instance, node_id)
562
562
 
563
563
  def add_node_type(
564
564
  self,
@@ -171,7 +171,8 @@ class CycleTemplates:
171
171
  ... )
172
172
  """
173
173
  if cycle_id is None:
174
- cycle_id = f"optimization_cycle_{int(time.time())}"
174
+ # Use timestamp with milliseconds for ID generation to ensure uniqueness
175
+ cycle_id = f"optimization_cycle_{int(time.time() * 1000)}"
175
176
 
176
177
  # Connect processor to evaluator
177
178
  workflow.connect(processor_node, evaluator_node)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kailash
3
- Version: 0.9.19
3
+ Version: 0.9.21
4
4
  Summary: Python SDK for the Kailash container-node architecture
5
5
  Home-page: https://github.com/integrum/kailash-python-sdk
6
6
  Author: Integrum
@@ -53,7 +53,6 @@ Requires-Dist: pre-commit>=4.2.0
53
53
  Requires-Dist: twine>=6.1.0
54
54
  Requires-Dist: ollama>=0.5.1
55
55
  Requires-Dist: sqlalchemy>=2.0.0
56
- Requires-Dist: psycopg2-binary>=2.9.0
57
56
  Requires-Dist: pymysql>=1.1.0
58
57
  Requires-Dist: aiosqlite>=0.19.0
59
58
  Requires-Dist: websockets>=12.0
@@ -70,7 +69,7 @@ Requires-Dist: qrcode>=8.2
70
69
  Requires-Dist: aiofiles>=24.1.0
71
70
  Requires-Dist: bcrypt>=4.3.0
72
71
  Requires-Dist: plotly>=6.2.0
73
- Requires-Dist: redis[asyncio]>=6.2.0
72
+ Requires-Dist: redis>=6.2.0
74
73
  Requires-Dist: faker>=37.4.0
75
74
  Requires-Dist: structlog>=25.4.0
76
75
  Requires-Dist: authlib>=1.6.0
@@ -86,6 +85,8 @@ Requires-Dist: seaborn>=0.13.2
86
85
  Requires-Dist: sqlparse>=0.5.3
87
86
  Requires-Dist: jsonschema>=4.24.0
88
87
  Requires-Dist: openai>=1.97.1
88
+ Requires-Dist: pymongo>=4.15.2
89
+ Requires-Dist: psycopg>=3.2.10
89
90
  Provides-Extra: dev
90
91
  Requires-Dist: pytest>=7.0; extra == "dev"
91
92
  Requires-Dist: pytest-cov>=3.0; extra == "dev"
@@ -121,28 +122,35 @@ Dynamic: requires-python
121
122
 
122
123
  ---
123
124
 
124
- ## 🔥 Latest Release: v0.9.10 (August 1, 2025)
125
+ ## 🔥 Latest Release: v0.9.21 (October 8, 2025)
125
126
 
126
- **License Update & IterativeLLMAgentNode API Simplification**
127
+ **AsyncSQL Event Loop Isolation Fix**
127
128
 
128
- ### 📄 License Changed to Apache 2.0 with Additional Terms
129
- - **Changed**: From MIT to Apache License 2.0 with Additional Terms
130
- - **Protection**: Prevents standalone commercial distribution of the SDK
131
- - **Freedom**: Allows commercial use of derivatives and integration into larger systems
132
- - **Patent Grant**: Includes Apache 2.0 patent protection clauses
129
+ ### 🐛 Critical Bug Fixes
130
+ - **Event Loop Isolation**: Fixed "Event loop is closed" errors in AsyncSQLDatabaseNode
131
+ - Automatic connection pool isolation per event loop
132
+ - Prevents pool sharing across different event loops (FastAPI, sequential workflows)
133
+ - Backward compatible - no code changes required
134
+ - <5% performance overhead
133
135
 
134
- ### 🤖 IterativeLLMAgentNode Improvements (v0.9.9)
135
- - **Removed**: Mock mode entirely - real MCP execution always enabled
136
- - **Simplified**: API by removing confusing `use_real_mcp` parameter
137
- - **Enhanced**: Graceful fallback when MCP tools unavailable
138
- - **Updated**: All documentation and examples with simplified API
136
+ ### Previous Release: v0.9.20 (October 6, 2025)
137
+ - **Mock Provider Bypass**: Removed hardcoded `if provider == "mock"` logic from LLMAgentNode
138
+ - **Tool Execution Flow**: Unified provider response generation for all providers
139
+ - **Provider Registry**: All providers now use consistent registry path
140
+
141
+ ### ✨ Enhancements
142
+ - **Custom Mock Providers**: Enables signature-aware mock providers (e.g., KaizenMockProvider)
143
+ - **Multi-Modal Foundation**: Foundation for vision/audio processing in Kaizen AI framework
144
+ - **Tool Call Generation**: MockProvider generates mock tool_calls for action-oriented messages
145
+ - **Enhanced Testing**: 510+ tests passing with custom mock providers
139
146
 
140
147
  ### 📦 Package Updates
141
- - **kailash**: v0.9.10 - License update
142
- - **kailash-nexus**: v1.0.6 - License update
143
- - **kailash-dataflow**: v0.3.7 - License update
148
+ - **kailash**: v0.9.20 - Provider registry fix & multi-modal support
149
+ - **kailash-kaizen**: v0.1.1 - AI agent framework (NEW!)
150
+ - **kailash-nexus**: v1.0.6 - Multi-channel platform
151
+ - **kailash-dataflow**: v0.5.0 - Database framework
144
152
 
145
- [Full Changelog](sdk-users/6-reference/changelogs/releases/v0.9.10-2025-08-01.md) | [Core SDK 0.9.10](https://pypi.org/project/kailash/0.9.10/) | [Nexus 1.0.6](https://pypi.org/project/kailash-nexus/1.0.6/) | [DataFlow 0.3.7](https://pypi.org/project/kailash-dataflow/0.3.7/)
153
+ [Full Changelog](sdk-users/6-reference/changelogs/releases/v0.9.20-provider-registry-fix.md) | [Core SDK 0.9.20](https://pypi.org/project/kailash/0.9.20/) | [Kaizen 0.1.1](https://pypi.org/project/kailash-kaizen/0.1.1/) | [Nexus 1.0.6](https://pypi.org/project/kailash-nexus/1.0.6/) | [DataFlow 0.5.0](https://pypi.org/project/kailash-dataflow/0.5.0/)
146
154
 
147
155
  ## 🎯 What Makes Kailash Different
148
156
 
@@ -1,4 +1,4 @@
1
- kailash/__init__.py,sha256=UXdg3RRcDvHRZQ_btbIDsx1ekoYuJmtoVuRJKbF-sRo,2928
1
+ kailash/__init__.py,sha256=C2Wda8HouzENpwGg80j0axK14KHtCoteXfA8a298b5U,2928
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
@@ -93,7 +93,7 @@ kailash/mcp_server/oauth.py,sha256=GFC2O2ueiTTI6V-91Huevhc3K8CxrHe22knuHfuCTqY,5
93
93
  kailash/mcp_server/protocol.py,sha256=NIdEwJT21JT9ItajXniPNvCbZtTbpqyOC_ZezqsguGE,35694
94
94
  kailash/mcp_server/registry_integration.py,sha256=B8CSLq_O1ea3cXrbVjC3bB_OFgHIP-KS9dk77mNM02I,19791
95
95
  kailash/mcp_server/server.py,sha256=yFp1F4QQl6gkTY_9JJWmiMiwfT-zACLJLubz-NR5sCw,108675
96
- kailash/mcp_server/subscriptions.py,sha256=UK0Ssjab-lHJ16DFPi6lmvLh5xMYNRZia0DgYb6aQ60,58586
96
+ kailash/mcp_server/subscriptions.py,sha256=-SWy1RnKUrBQ1y8ooeTiA2ODhxBbzfpsrtb8HtkhTYg,58591
97
97
  kailash/mcp_server/transports.py,sha256=fBa7CTVYTDb0ZbBQTsZ2d8rKvcVuqBIteczq8eqarr4,49919
98
98
  kailash/mcp_server/servers/ai_registry.py,sha256=IdF_keUuJlMsvjLjSAykxxbm46K4qA7eCj7T-lYSrzk,10007
99
99
  kailash/mcp_server/utils/__init__.py,sha256=R20N-iiKXUPxc9MOh6vPO1vIfkPmwhEQ5KNFgGd4xSs,771
@@ -155,7 +155,7 @@ kailash/monitoring/__init__.py,sha256=w7We20bpBdcYR3PTfN9lkep8fPEc3T2eenUkNwjdw_
155
155
  kailash/monitoring/alerts.py,sha256=Hk3Xs0EEkOIBH2ZhlejJBOsLYaPlvRejAAEGqNQISc0,21400
156
156
  kailash/monitoring/asyncsql_metrics.py,sha256=jj9M8D5qHoS3zEFfZYsUCWsy5kb-J5-iYVacmNUaGjE,9577
157
157
  kailash/monitoring/metrics.py,sha256=SiAnL3o6K0QaJHgfAuWBa-0pTkW5zymhuPEsj4bgOgM,22022
158
- kailash/nodes/__init__.py,sha256=zn4M0f-sIPAq8bG5golQIxmEY8lG5d55Kzg8UNL2lAY,6392
158
+ kailash/nodes/__init__.py,sha256=dBnEwrop0cPblHxSOtVWAKCDzhRtcyQVv9j_YGWxczQ,6410
159
159
  kailash/nodes/__init___original.py,sha256=p2KSo0dyUBCLClU123qpQ0tyv5S_36PTxosNyW58nyY,1031
160
160
  kailash/nodes/base.py,sha256=GR2E1fWf8j1yMvJic7m2NAih7kjY1NtoDi47hHwoZ40,85437
161
161
  kailash/nodes/base_async.py,sha256=whxepCiVplrltfzEQuabmnGCpEV5WgfqwgxbLdCyiDk,8864
@@ -177,14 +177,13 @@ kailash/nodes/admin/transaction_utils.py,sha256=IAAdIiQ5Q4kTT5ul4hv1iSfoXG3CeFAk
177
177
  kailash/nodes/admin/user_management.py,sha256=Al9mKgTx3ASDSefZaIcPxL4zSjASI3cGdZIs33uwpvg,54707
178
178
  kailash/nodes/ai/__init__.py,sha256=1mH94Ap5Zo0sUFNNZbMQf3h_KmyS2fquCTFMPvdJLoc,2725
179
179
  kailash/nodes/ai/a2a.py,sha256=g3QIeCefWpcmQ3RpuoTAnCj9Q8145ieV3NyEfGsyOno,138552
180
- kailash/nodes/ai/a2a_backup.py,sha256=fDSnihMFQ6MuhKSzL9ueWGAQLrKZQRkq9HqArdotf_w,70048
181
180
  kailash/nodes/ai/agents.py,sha256=CRA3cdapQjpuvOniXUh6ZVWAlRxUIepVw1BROW6QzdY,20373
182
- kailash/nodes/ai/ai_providers.py,sha256=egfiOZzPmZ10d3wBCJ6ST4tRFrrtq0kt1VyCqxVpxas,65390
181
+ kailash/nodes/ai/ai_providers.py,sha256=XdkZlG7TJcQWoPEYLBy65jjtkOTxOpjl7MFO5MfZc6U,76627
183
182
  kailash/nodes/ai/embedding_generator.py,sha256=akGCzz7zLRSziqEQCiPwL2qWhRWxuM_1RQh-YtVEddw,31879
184
183
  kailash/nodes/ai/hybrid_search.py,sha256=k26uDDP_bwrIpv7Yl7PBCPvWSyQEmTlBjI1IpbgDsO4,35446
185
184
  kailash/nodes/ai/intelligent_agent_orchestrator.py,sha256=LvBqMKc64zSxFWVCjbLKKel2QwEzoTeJAEgna7rZw00,83097
186
185
  kailash/nodes/ai/iterative_llm_agent.py,sha256=h8iP1KFhB_eCDs7UvmY_9y0OUBuprYMj2MLM6dR0W2c,100287
187
- kailash/nodes/ai/llm_agent.py,sha256=p7_WFXrkvezUleU8mLPE6JzGd3qRhWCqFIBBiMRnGYA,96943
186
+ kailash/nodes/ai/llm_agent.py,sha256=-3K5BuMsPk_-0gIc-_pg95-cgh8yXZ5CaQvE91Wu3nw,99307
188
187
  kailash/nodes/ai/models.py,sha256=wsEeUTuegy87mnLtKgSTg7ggCXvC1n3MsL-iZ4qujHs,16393
189
188
  kailash/nodes/ai/self_organizing.py,sha256=B7NwKaBW8OHQBf5b0F9bSs8Wm-5BDJ9IjIkxS9h00mg,62885
190
189
  kailash/nodes/ai/semantic_memory.py,sha256=ZTXIgxwMheux712cN__cNrQ3VgHaKcDyfQv_Gto7MRM,18644
@@ -214,13 +213,13 @@ kailash/nodes/cache/cache_invalidation.py,sha256=IUvxrRj3K5EF29Z2EaKl7t6Uze_cssn
214
213
  kailash/nodes/cache/redis_pool_manager.py,sha256=GR82GCWxo_gAzRE-091OB6AhKre8CTwM3OoePLb2gvE,21574
215
214
  kailash/nodes/code/__init__.py,sha256=yhEwuMjUEPFfe6hMGMd4E4gZdLUuf2JEQ7knYapiM4o,1283
216
215
  kailash/nodes/code/async_python.py,sha256=Ai-iMpmz-sAori73JBk0wZtqmwtmF2GNPDxqB04I2Ck,37058
217
- kailash/nodes/code/python.py,sha256=fHrPWUPsIVd6yUM8KxmID9a0Bt5ehXU9dAiZz44aVU4,62481
216
+ kailash/nodes/code/python.py,sha256=rHBynVhV16G9AOQMZtLnpwTkp-wxsGe69BAjVZ4X6hg,70224
218
217
  kailash/nodes/compliance/__init__.py,sha256=6a_FL4ofc8MAVuZ-ARW5uYenZLS4mBFVM9AI2QsnoF8,214
219
218
  kailash/nodes/compliance/data_retention.py,sha256=90bH_eGwlcDzUdklAJeXQM-RcuLUGQFQ5fgHOK8a4qk,69443
220
219
  kailash/nodes/compliance/gdpr.py,sha256=ZMoHZjAo4QtGwtFCzGMrAUBFV3TbZOnJ5DZGZS87Bas,70548
221
220
  kailash/nodes/data/__init__.py,sha256=f0h4ysvXxlyFcNJLvDyXrgJ0ixwDF1cS0pJ2QNPakhg,5213
222
221
  kailash/nodes/data/async_connection.py,sha256=wfArHs9svU48bxGZIiixSV2YVn9cukNgEjagwTRu6J4,17250
223
- kailash/nodes/data/async_sql.py,sha256=9C-XRTDrzpVwFRrI13ym539UajT0Qgh9jmIjisDPi28,188864
222
+ kailash/nodes/data/async_sql.py,sha256=34jUqCiUaNMVynCSteTIT8mZUs2SanZoKdsyyyZf51E,191567
224
223
  kailash/nodes/data/async_vector.py,sha256=HtwQLO25IXu8Vq80qzU8rMkUAKPQ2qM0x8YxjXHlygU,21005
225
224
  kailash/nodes/data/bulk_operations.py,sha256=WVopmosVkIlweFxVt3boLdCPc93EqpYyQ1Ez9mCIt0c,34453
226
225
  kailash/nodes/data/directory.py,sha256=fbfLqD_ijRubk-4xew3604QntPsyDxqaF4k6TpfyjDg,9923
@@ -399,7 +398,7 @@ kailash/visualization/reports.py,sha256=D7kJ0flHr16d-qSEq8vnw20N8u_dgTrXtKVSXVm8
399
398
  kailash/workflow/__init__.py,sha256=DDQDE9K6RmbX6479guNLLgjiVVV-gQERRvCEJWSVlsM,1836
400
399
  kailash/workflow/async_builder.py,sha256=iv8bDJHdWAUZ77SyMo6sucd92dTdtXesdxycrSE7mM4,20613
401
400
  kailash/workflow/async_patterns.py,sha256=X0ZDXwr6UAu0WC1xnCB7-0V1-tRbKs9UI4JqaBCB6tE,22824
402
- kailash/workflow/builder.py,sha256=SAhgUD-4RX0r0r8Gxk8dm19Q_R7KQOm4YhvSNvnf9hQ,51069
401
+ kailash/workflow/builder.py,sha256=mHWfoHsq4W5DvJmv3b_vMDeVXqqpNHXO6U3Kuvk54tI,51079
403
402
  kailash/workflow/contracts.py,sha256=Uch-s2SC-NYrg0n2zgljgkyFHf4bufY4OydFuIfAk7E,13442
404
403
  kailash/workflow/convergence.py,sha256=vfIDR-uNaQE-LVUEzrRtfgKPgX9gL0nLNH-nTg5ra-c,10031
405
404
  kailash/workflow/cycle_analyzer.py,sha256=BGBpgdB-g0-KRI65sVAvHV4lxfoCzMt4uKOHbw8GXT4,32596
@@ -420,14 +419,14 @@ kailash/workflow/resilience.py,sha256=Ecef4gBg-QWP369a_xfzQnVWhHryvEcO2RSFVSriLJ
420
419
  kailash/workflow/runner.py,sha256=l6jb-H7DwbRlvQ3H3SuTs70rut-u7H3Gi8nybKCEjZU,10795
421
420
  kailash/workflow/safety.py,sha256=pS5GKu7UdkzFZcb16Dn-0jBxjULDU-59_M0CbUVMVyw,11298
422
421
  kailash/workflow/state.py,sha256=UTZxs5-Ona6uvBhx1__i6-RX8gB4qazkBIWE7uyRmWQ,7600
423
- kailash/workflow/templates.py,sha256=XQMAKZXC2dlxgMMQhSEOWAF3hIbe9JJt9j_THchhAm8,48486
422
+ kailash/workflow/templates.py,sha256=aZQzEPQD368nN0x0ICQlRKmAr2FqTxIOUa-7rb7EUWI,48578
424
423
  kailash/workflow/type_inference.py,sha256=i1F7Yd_Z3elTXrthsLpqGbOnQBIVVVEjhRpI0HrIjd0,24492
425
424
  kailash/workflow/validation.py,sha256=LdbIPQSokCqSLfWTBhJR82pa_0va44pcVu9dpEM4rvY,45177
426
425
  kailash/workflow/visualization.py,sha256=nHBW-Ai8QBMZtn2Nf3EE1_aiMGi9S6Ui_BfpA5KbJPU,23187
427
- kailash-0.9.19.dist-info/licenses/LICENSE,sha256=9GYZHXVUmx6FdFRNzOeE_w7a_aEGeYbqTVmFtJlrbGk,13438
428
- kailash-0.9.19.dist-info/licenses/NOTICE,sha256=9ssIK4LcHSTFqriXGdteMpBPTS1rSLlYtjppZ_bsjZ0,723
429
- kailash-0.9.19.dist-info/METADATA,sha256=RY2liVVkhKdErnyayfo4_vH2OyMVKgvtvimhAT7JWvA,23528
430
- kailash-0.9.19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
431
- kailash-0.9.19.dist-info/entry_points.txt,sha256=M_q3b8PG5W4XbhSgESzIJjh3_4OBKtZFYFsOdkr2vO4,45
432
- kailash-0.9.19.dist-info/top_level.txt,sha256=z7GzH2mxl66498pVf5HKwo5wwfPtt9Aq95uZUpH6JV0,8
433
- kailash-0.9.19.dist-info/RECORD,,
426
+ kailash-0.9.21.dist-info/licenses/LICENSE,sha256=9GYZHXVUmx6FdFRNzOeE_w7a_aEGeYbqTVmFtJlrbGk,13438
427
+ kailash-0.9.21.dist-info/licenses/NOTICE,sha256=9ssIK4LcHSTFqriXGdteMpBPTS1rSLlYtjppZ_bsjZ0,723
428
+ kailash-0.9.21.dist-info/METADATA,sha256=LfBFe4bjx6PGjbDuUUawKQhpMJ57QlbRDWEY7oUkuIk,24027
429
+ kailash-0.9.21.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
430
+ kailash-0.9.21.dist-info/entry_points.txt,sha256=M_q3b8PG5W4XbhSgESzIJjh3_4OBKtZFYFsOdkr2vO4,45
431
+ kailash-0.9.21.dist-info/top_level.txt,sha256=z7GzH2mxl66498pVf5HKwo5wwfPtt9Aq95uZUpH6JV0,8
432
+ kailash-0.9.21.dist-info/RECORD,,