kailash 0.3.2__py3-none-any.whl → 0.4.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.
Files changed (151) hide show
  1. kailash/__init__.py +33 -1
  2. kailash/access_control/__init__.py +129 -0
  3. kailash/access_control/managers.py +461 -0
  4. kailash/access_control/rule_evaluators.py +467 -0
  5. kailash/access_control_abac.py +825 -0
  6. kailash/config/__init__.py +27 -0
  7. kailash/config/database_config.py +359 -0
  8. kailash/database/__init__.py +28 -0
  9. kailash/database/execution_pipeline.py +499 -0
  10. kailash/middleware/__init__.py +306 -0
  11. kailash/middleware/auth/__init__.py +33 -0
  12. kailash/middleware/auth/access_control.py +436 -0
  13. kailash/middleware/auth/auth_manager.py +422 -0
  14. kailash/middleware/auth/jwt_auth.py +477 -0
  15. kailash/middleware/auth/kailash_jwt_auth.py +616 -0
  16. kailash/middleware/communication/__init__.py +37 -0
  17. kailash/middleware/communication/ai_chat.py +989 -0
  18. kailash/middleware/communication/api_gateway.py +802 -0
  19. kailash/middleware/communication/events.py +470 -0
  20. kailash/middleware/communication/realtime.py +710 -0
  21. kailash/middleware/core/__init__.py +21 -0
  22. kailash/middleware/core/agent_ui.py +890 -0
  23. kailash/middleware/core/schema.py +643 -0
  24. kailash/middleware/core/workflows.py +396 -0
  25. kailash/middleware/database/__init__.py +63 -0
  26. kailash/middleware/database/base.py +113 -0
  27. kailash/middleware/database/base_models.py +525 -0
  28. kailash/middleware/database/enums.py +106 -0
  29. kailash/middleware/database/migrations.py +12 -0
  30. kailash/{api/database.py → middleware/database/models.py} +183 -291
  31. kailash/middleware/database/repositories.py +685 -0
  32. kailash/middleware/database/session_manager.py +19 -0
  33. kailash/middleware/mcp/__init__.py +38 -0
  34. kailash/middleware/mcp/client_integration.py +585 -0
  35. kailash/middleware/mcp/enhanced_server.py +576 -0
  36. kailash/nodes/__init__.py +27 -3
  37. kailash/nodes/admin/__init__.py +42 -0
  38. kailash/nodes/admin/audit_log.py +794 -0
  39. kailash/nodes/admin/permission_check.py +864 -0
  40. kailash/nodes/admin/role_management.py +823 -0
  41. kailash/nodes/admin/security_event.py +1523 -0
  42. kailash/nodes/admin/user_management.py +944 -0
  43. kailash/nodes/ai/a2a.py +24 -7
  44. kailash/nodes/ai/ai_providers.py +248 -40
  45. kailash/nodes/ai/embedding_generator.py +11 -11
  46. kailash/nodes/ai/intelligent_agent_orchestrator.py +99 -11
  47. kailash/nodes/ai/llm_agent.py +436 -5
  48. kailash/nodes/ai/self_organizing.py +85 -10
  49. kailash/nodes/ai/vision_utils.py +148 -0
  50. kailash/nodes/alerts/__init__.py +26 -0
  51. kailash/nodes/alerts/base.py +234 -0
  52. kailash/nodes/alerts/discord.py +499 -0
  53. kailash/nodes/api/auth.py +287 -6
  54. kailash/nodes/api/rest.py +151 -0
  55. kailash/nodes/auth/__init__.py +17 -0
  56. kailash/nodes/auth/directory_integration.py +1228 -0
  57. kailash/nodes/auth/enterprise_auth_provider.py +1328 -0
  58. kailash/nodes/auth/mfa.py +2338 -0
  59. kailash/nodes/auth/risk_assessment.py +872 -0
  60. kailash/nodes/auth/session_management.py +1093 -0
  61. kailash/nodes/auth/sso.py +1040 -0
  62. kailash/nodes/base.py +344 -13
  63. kailash/nodes/base_cycle_aware.py +4 -2
  64. kailash/nodes/base_with_acl.py +1 -1
  65. kailash/nodes/code/python.py +283 -10
  66. kailash/nodes/compliance/__init__.py +9 -0
  67. kailash/nodes/compliance/data_retention.py +1888 -0
  68. kailash/nodes/compliance/gdpr.py +2004 -0
  69. kailash/nodes/data/__init__.py +22 -2
  70. kailash/nodes/data/async_connection.py +469 -0
  71. kailash/nodes/data/async_sql.py +757 -0
  72. kailash/nodes/data/async_vector.py +598 -0
  73. kailash/nodes/data/readers.py +767 -0
  74. kailash/nodes/data/retrieval.py +360 -1
  75. kailash/nodes/data/sharepoint_graph.py +397 -21
  76. kailash/nodes/data/sql.py +94 -5
  77. kailash/nodes/data/streaming.py +68 -8
  78. kailash/nodes/data/vector_db.py +54 -4
  79. kailash/nodes/enterprise/__init__.py +13 -0
  80. kailash/nodes/enterprise/batch_processor.py +741 -0
  81. kailash/nodes/enterprise/data_lineage.py +497 -0
  82. kailash/nodes/logic/convergence.py +31 -9
  83. kailash/nodes/logic/operations.py +14 -3
  84. kailash/nodes/mixins/__init__.py +8 -0
  85. kailash/nodes/mixins/event_emitter.py +201 -0
  86. kailash/nodes/mixins/mcp.py +9 -4
  87. kailash/nodes/mixins/security.py +165 -0
  88. kailash/nodes/monitoring/__init__.py +7 -0
  89. kailash/nodes/monitoring/performance_benchmark.py +2497 -0
  90. kailash/nodes/rag/__init__.py +284 -0
  91. kailash/nodes/rag/advanced.py +1615 -0
  92. kailash/nodes/rag/agentic.py +773 -0
  93. kailash/nodes/rag/conversational.py +999 -0
  94. kailash/nodes/rag/evaluation.py +875 -0
  95. kailash/nodes/rag/federated.py +1188 -0
  96. kailash/nodes/rag/graph.py +721 -0
  97. kailash/nodes/rag/multimodal.py +671 -0
  98. kailash/nodes/rag/optimized.py +933 -0
  99. kailash/nodes/rag/privacy.py +1059 -0
  100. kailash/nodes/rag/query_processing.py +1335 -0
  101. kailash/nodes/rag/realtime.py +764 -0
  102. kailash/nodes/rag/registry.py +547 -0
  103. kailash/nodes/rag/router.py +837 -0
  104. kailash/nodes/rag/similarity.py +1854 -0
  105. kailash/nodes/rag/strategies.py +566 -0
  106. kailash/nodes/rag/workflows.py +575 -0
  107. kailash/nodes/security/__init__.py +19 -0
  108. kailash/nodes/security/abac_evaluator.py +1411 -0
  109. kailash/nodes/security/audit_log.py +103 -0
  110. kailash/nodes/security/behavior_analysis.py +1893 -0
  111. kailash/nodes/security/credential_manager.py +401 -0
  112. kailash/nodes/security/rotating_credentials.py +760 -0
  113. kailash/nodes/security/security_event.py +133 -0
  114. kailash/nodes/security/threat_detection.py +1103 -0
  115. kailash/nodes/testing/__init__.py +9 -0
  116. kailash/nodes/testing/credential_testing.py +499 -0
  117. kailash/nodes/transform/__init__.py +10 -2
  118. kailash/nodes/transform/chunkers.py +592 -1
  119. kailash/nodes/transform/processors.py +484 -14
  120. kailash/nodes/validation.py +321 -0
  121. kailash/runtime/access_controlled.py +1 -1
  122. kailash/runtime/async_local.py +41 -7
  123. kailash/runtime/docker.py +1 -1
  124. kailash/runtime/local.py +474 -55
  125. kailash/runtime/parallel.py +1 -1
  126. kailash/runtime/parallel_cyclic.py +1 -1
  127. kailash/runtime/testing.py +210 -2
  128. kailash/security.py +1 -1
  129. kailash/utils/migrations/__init__.py +25 -0
  130. kailash/utils/migrations/generator.py +433 -0
  131. kailash/utils/migrations/models.py +231 -0
  132. kailash/utils/migrations/runner.py +489 -0
  133. kailash/utils/secure_logging.py +342 -0
  134. kailash/workflow/__init__.py +16 -0
  135. kailash/workflow/cyclic_runner.py +3 -4
  136. kailash/workflow/graph.py +70 -2
  137. kailash/workflow/resilience.py +249 -0
  138. kailash/workflow/templates.py +726 -0
  139. {kailash-0.3.2.dist-info → kailash-0.4.1.dist-info}/METADATA +256 -20
  140. kailash-0.4.1.dist-info/RECORD +227 -0
  141. kailash/api/__init__.py +0 -17
  142. kailash/api/__main__.py +0 -6
  143. kailash/api/studio_secure.py +0 -893
  144. kailash/mcp/__main__.py +0 -13
  145. kailash/mcp/server_new.py +0 -336
  146. kailash/mcp/servers/__init__.py +0 -12
  147. kailash-0.3.2.dist-info/RECORD +0 -136
  148. {kailash-0.3.2.dist-info → kailash-0.4.1.dist-info}/WHEEL +0 -0
  149. {kailash-0.3.2.dist-info → kailash-0.4.1.dist-info}/entry_points.txt +0 -0
  150. {kailash-0.3.2.dist-info → kailash-0.4.1.dist-info}/licenses/LICENSE +0 -0
  151. {kailash-0.3.2.dist-info → kailash-0.4.1.dist-info}/top_level.txt +0 -0
@@ -1,17 +1,13 @@
1
1
  """
2
- Database models and storage backend for Kailash Workflow Studio.
2
+ Enhanced Database Models for Kailash Middleware
3
3
 
4
- This module provides:
5
- - SQLAlchemy models for workflows, nodes, executions, and user data
6
- - Database initialization and migration support
7
- - Repository classes for data access
4
+ Consolidates and enhances existing database models from api/database.py
5
+ with middleware-specific features and event integration.
8
6
  """
9
7
 
10
8
  import uuid
11
- from contextlib import contextmanager
12
- from datetime import UTC, datetime
13
- from pathlib import Path
14
- from typing import Any
9
+ from datetime import datetime, timezone
10
+ from typing import Any, Dict, List, Optional
15
11
 
16
12
  from sqlalchemy import (
17
13
  JSON,
@@ -25,16 +21,14 @@ from sqlalchemy import (
25
21
  Text,
26
22
  create_engine,
27
23
  )
28
- from sqlalchemy.engine import Engine
29
- from sqlalchemy.ext.declarative import declarative_base
30
- from sqlalchemy.orm import Session, relationship, sessionmaker
24
+ from sqlalchemy.orm import declarative_base, relationship
31
25
  from sqlalchemy.sql import func
32
26
 
33
27
  Base = declarative_base()
34
28
 
35
29
 
36
- class Workflow(Base):
37
- """Workflow database model"""
30
+ class WorkflowModel(Base):
31
+ """Enhanced workflow model with middleware integration"""
38
32
 
39
33
  __tablename__ = "workflows"
40
34
 
@@ -45,26 +39,41 @@ class Workflow(Base):
45
39
  definition = Column(JSON, nullable=False)
46
40
  version = Column(Integer, default=1)
47
41
  is_published = Column(Boolean, default=False)
42
+
43
+ # Middleware enhancements
44
+ session_id = Column(String(36), nullable=True, index=True) # Associated session
45
+ agent_ui_config = Column(JSON) # UI-specific configuration
46
+ real_time_enabled = Column(Boolean, default=True) # Enable real-time updates
47
+
48
+ # Metadata
48
49
  created_by = Column(String(255))
49
50
  created_at = Column(DateTime, default=func.now())
50
51
  updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
51
52
 
52
53
  # Relationships
53
54
  executions = relationship(
54
- "WorkflowExecution", back_populates="workflow", cascade="all, delete-orphan"
55
+ "WorkflowExecutionModel",
56
+ back_populates="workflow",
57
+ cascade="all, delete-orphan",
55
58
  )
56
59
  versions = relationship(
57
- "WorkflowVersion", back_populates="workflow", cascade="all, delete-orphan"
60
+ "WorkflowVersionModel", back_populates="workflow", cascade="all, delete-orphan"
61
+ )
62
+ permissions = relationship(
63
+ "WorkflowPermissionModel",
64
+ back_populates="workflow",
65
+ cascade="all, delete-orphan",
58
66
  )
59
67
 
60
68
  __table_args__ = (
61
69
  Index("idx_workflow_tenant_created", "tenant_id", "created_at"),
62
70
  Index("idx_workflow_tenant_name", "tenant_id", "name"),
71
+ Index("idx_workflow_session", "session_id"),
63
72
  )
64
73
 
65
74
 
66
- class WorkflowVersion(Base):
67
- """Workflow version history"""
75
+ class WorkflowVersionModel(Base):
76
+ """Enhanced workflow version with change tracking"""
68
77
 
69
78
  __tablename__ = "workflow_versions"
70
79
 
@@ -73,19 +82,25 @@ class WorkflowVersion(Base):
73
82
  version = Column(Integer, nullable=False)
74
83
  definition = Column(JSON, nullable=False)
75
84
  change_message = Column(Text)
85
+
86
+ # Middleware enhancements
87
+ diff_data = Column(JSON) # Structured diff from previous version
88
+ migration_notes = Column(Text) # Notes about breaking changes
89
+
90
+ # Metadata
76
91
  created_by = Column(String(255))
77
92
  created_at = Column(DateTime, default=func.now())
78
93
 
79
94
  # Relationships
80
- workflow = relationship("Workflow", back_populates="versions")
95
+ workflow = relationship("WorkflowModel", back_populates="versions")
81
96
 
82
97
  __table_args__ = (
83
98
  Index("idx_version_workflow_version", "workflow_id", "version", unique=True),
84
99
  )
85
100
 
86
101
 
87
- class CustomNode(Base):
88
- """Custom node definitions created by users"""
102
+ class CustomNodeModel(Base):
103
+ """Enhanced custom node with middleware features"""
89
104
 
90
105
  __tablename__ = "custom_nodes"
91
106
 
@@ -103,9 +118,14 @@ class CustomNode(Base):
103
118
  outputs = Column(JSON) # Output port definitions
104
119
 
105
120
  # Implementation
106
- implementation_type = Column(String(50)) # 'python', 'workflow', 'api'
121
+ implementation_type = Column(String(50)) # 'python', 'workflow', 'api', 'kailash'
107
122
  implementation = Column(JSON) # Implementation details
108
123
 
124
+ # Middleware enhancements
125
+ middleware_config = Column(JSON) # Middleware-specific configuration
126
+ real_time_capable = Column(Boolean, default=False) # Supports real-time updates
127
+ event_types = Column(JSON) # List of event types this node can emit
128
+
109
129
  # Metadata
110
130
  is_published = Column(Boolean, default=False)
111
131
  created_by = Column(String(255))
@@ -118,8 +138,8 @@ class CustomNode(Base):
118
138
  )
119
139
 
120
140
 
121
- class WorkflowExecution(Base):
122
- """Workflow execution history"""
141
+ class WorkflowExecutionModel(Base):
142
+ """Enhanced execution model with real-time tracking"""
123
143
 
124
144
  __tablename__ = "workflow_executions"
125
145
 
@@ -135,6 +155,12 @@ class WorkflowExecution(Base):
135
155
  result = Column(JSON)
136
156
  error = Column(Text)
137
157
 
158
+ # Middleware enhancements
159
+ session_id = Column(String(36), nullable=True, index=True) # Associated session
160
+ real_time_events = Column(JSON) # List of real-time events emitted
161
+ agent_ui_data = Column(JSON) # UI-specific execution data
162
+ execution_metrics = Column(JSON) # Performance and resource metrics
163
+
138
164
  # Performance metrics
139
165
  started_at = Column(DateTime)
140
166
  completed_at = Column(DateTime)
@@ -144,17 +170,18 @@ class WorkflowExecution(Base):
144
170
  node_executions = Column(JSON) # Detailed per-node execution data
145
171
 
146
172
  # Relationships
147
- workflow = relationship("Workflow", back_populates="executions")
173
+ workflow = relationship("WorkflowModel", back_populates="executions")
148
174
 
149
175
  __table_args__ = (
150
176
  Index("idx_execution_tenant_started", "tenant_id", "started_at"),
151
177
  Index("idx_execution_workflow_started", "workflow_id", "started_at"),
152
178
  Index("idx_execution_status", "status"),
179
+ Index("idx_execution_session", "session_id"),
153
180
  )
154
181
 
155
182
 
156
- class UserPreferences(Base):
157
- """User preferences and settings"""
183
+ class UserPreferencesModel(Base):
184
+ """Enhanced user preferences with middleware features"""
158
185
 
159
186
  __tablename__ = "user_preferences"
160
187
 
@@ -171,6 +198,11 @@ class UserPreferences(Base):
171
198
  favorite_nodes = Column(JSON)
172
199
  recent_workflows = Column(JSON)
173
200
 
201
+ # Middleware enhancements
202
+ real_time_preferences = Column(JSON) # Real-time update preferences
203
+ agent_ui_settings = Column(JSON) # Agent-UI specific settings
204
+ notification_settings = Column(JSON) # Event notification preferences
205
+
174
206
  created_at = Column(DateTime, default=func.now())
175
207
  updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
176
208
 
@@ -179,8 +211,8 @@ class UserPreferences(Base):
179
211
  )
180
212
 
181
213
 
182
- class WorkflowTemplate(Base):
183
- """Pre-built workflow templates"""
214
+ class WorkflowTemplateModel(Base):
215
+ """Enhanced workflow templates with middleware integration"""
184
216
 
185
217
  __tablename__ = "workflow_templates"
186
218
 
@@ -195,6 +227,11 @@ class WorkflowTemplate(Base):
195
227
  definition = Column(JSON, nullable=False)
196
228
  default_parameters = Column(JSON)
197
229
 
230
+ # Middleware enhancements
231
+ middleware_features = Column(JSON) # Required middleware features
232
+ agent_ui_template = Column(JSON) # Agent-UI template configuration
233
+ real_time_template = Column(JSON) # Real-time update template
234
+
198
235
  # Metadata
199
236
  is_public = Column(Boolean, default=False)
200
237
  usage_count = Column(Integer, default=0)
@@ -208,8 +245,8 @@ class WorkflowTemplate(Base):
208
245
  )
209
246
 
210
247
 
211
- class WorkflowPermission(Base):
212
- """Workflow-level permissions"""
248
+ class WorkflowPermissionModel(Base):
249
+ """Enhanced workflow permissions with middleware access control"""
213
250
 
214
251
  __tablename__ = "workflow_permissions"
215
252
 
@@ -233,13 +270,18 @@ class WorkflowPermission(Base):
233
270
  # Conditions (JSON object for flexibility)
234
271
  conditions = Column(JSON)
235
272
 
273
+ # Middleware enhancements
274
+ session_restrictions = Column(JSON) # Session-based restrictions
275
+ real_time_permissions = Column(JSON) # Real-time access permissions
276
+ agent_ui_permissions = Column(JSON) # Agent-UI specific permissions
277
+
236
278
  # Metadata
237
279
  created_by = Column(String(255))
238
280
  created_at = Column(DateTime, default=func.now())
239
281
  expires_at = Column(DateTime, nullable=True)
240
282
 
241
283
  # Relationships
242
- workflow = relationship("Workflow", backref="permissions")
284
+ workflow = relationship("WorkflowModel", back_populates="permissions")
243
285
 
244
286
  __table_args__ = (
245
287
  Index("idx_workflow_perm_workflow", "workflow_id"),
@@ -248,8 +290,8 @@ class WorkflowPermission(Base):
248
290
  )
249
291
 
250
292
 
251
- class NodePermission(Base):
252
- """Node-level permissions"""
293
+ class NodePermissionModel(Base):
294
+ """Enhanced node permissions with middleware features"""
253
295
 
254
296
  __tablename__ = "node_permissions"
255
297
 
@@ -274,13 +316,17 @@ class NodePermission(Base):
274
316
  masked_fields = Column(JSON) # Fields to mask in output
275
317
  redirect_node = Column(String(255)) # Alternative node if access denied
276
318
 
319
+ # Middleware enhancements
320
+ real_time_masking = Column(JSON) # Real-time output masking rules
321
+ event_filtering = Column(JSON) # Event filtering rules for this node
322
+
277
323
  # Metadata
278
324
  created_by = Column(String(255))
279
325
  created_at = Column(DateTime, default=func.now())
280
326
  expires_at = Column(DateTime, nullable=True)
281
327
 
282
328
  # Relationships
283
- workflow = relationship("Workflow", backref="node_permissions")
329
+ workflow = relationship("WorkflowModel", backref="node_permissions")
284
330
 
285
331
  __table_args__ = (
286
332
  Index("idx_node_perm_workflow", "workflow_id"),
@@ -290,8 +336,8 @@ class NodePermission(Base):
290
336
  )
291
337
 
292
338
 
293
- class AccessLog(Base):
294
- """Audit log for access attempts"""
339
+ class AccessLogModel(Base):
340
+ """Enhanced access log with middleware event integration"""
295
341
 
296
342
  __tablename__ = "access_logs"
297
343
 
@@ -300,7 +346,7 @@ class AccessLog(Base):
300
346
  user_id = Column(String(36), nullable=False, index=True)
301
347
 
302
348
  # What was accessed?
303
- resource_type = Column(String(50), nullable=False) # workflow, node
349
+ resource_type = Column(String(50), nullable=False) # workflow, node, session, api
304
350
  resource_id = Column(String(255), nullable=False)
305
351
  permission = Column(String(50), nullable=False)
306
352
 
@@ -313,17 +359,25 @@ class AccessLog(Base):
313
359
  user_agent = Column(String(255))
314
360
  session_id = Column(String(36))
315
361
 
362
+ # Middleware enhancements
363
+ event_id = Column(String(36)) # Associated middleware event
364
+ real_time_logged = Column(
365
+ Boolean, default=False
366
+ ) # Whether logged to real-time stream
367
+ agent_ui_context = Column(JSON) # Agent-UI specific context
368
+
316
369
  # Timestamp
317
370
  timestamp = Column(DateTime, default=func.now(), index=True)
318
371
 
319
372
  __table_args__ = (
320
373
  Index("idx_access_log_user_time", "user_id", "timestamp"),
321
374
  Index("idx_access_log_resource", "resource_type", "resource_id", "timestamp"),
375
+ Index("idx_access_log_event", "event_id"),
322
376
  )
323
377
 
324
378
 
325
- class UserGroup(Base):
326
- """User groups for permission management"""
379
+ class UserGroupModel(Base):
380
+ """Enhanced user groups with middleware features"""
327
381
 
328
382
  __tablename__ = "user_groups"
329
383
 
@@ -335,6 +389,11 @@ class UserGroup(Base):
335
389
  # Group permissions (can be inherited)
336
390
  permissions = Column(JSON)
337
391
 
392
+ # Middleware enhancements
393
+ middleware_permissions = Column(JSON) # Middleware-specific permissions
394
+ real_time_access = Column(JSON) # Real-time feature access
395
+ agent_ui_access = Column(JSON) # Agent-UI access configuration
396
+
338
397
  # Metadata
339
398
  created_by = Column(String(255))
340
399
  created_at = Column(DateTime, default=func.now())
@@ -342,14 +401,14 @@ class UserGroup(Base):
342
401
 
343
402
  # Relationships
344
403
  members = relationship(
345
- "UserGroupMember", back_populates="group", cascade="all, delete-orphan"
404
+ "UserGroupMemberModel", back_populates="group", cascade="all, delete-orphan"
346
405
  )
347
406
 
348
407
  __table_args__ = (Index("idx_group_tenant_name", "tenant_id", "name", unique=True),)
349
408
 
350
409
 
351
- class UserGroupMember(Base):
352
- """User membership in groups"""
410
+ class UserGroupMemberModel(Base):
411
+ """Enhanced group membership with middleware tracking"""
353
412
 
354
413
  __tablename__ = "user_group_members"
355
414
 
@@ -362,8 +421,11 @@ class UserGroupMember(Base):
362
421
  joined_at = Column(DateTime, default=func.now())
363
422
  added_by = Column(String(255))
364
423
 
424
+ # Middleware enhancements
425
+ middleware_role_overrides = Column(JSON) # Role overrides for middleware features
426
+
365
427
  # Relationships
366
- group = relationship("UserGroup", back_populates="members")
428
+ group = relationship("UserGroupModel", back_populates="members")
367
429
 
368
430
  __table_args__ = (
369
431
  Index("idx_group_member", "group_id", "user_id", unique=True),
@@ -371,250 +433,80 @@ class UserGroupMember(Base):
371
433
  )
372
434
 
373
435
 
374
- # Repository classes for data access
375
- class WorkflowRepository:
376
- """Repository for workflow operations"""
377
-
378
- def __init__(self, session: Session):
379
- self.session = session
380
-
381
- def create(
382
- self,
383
- tenant_id: str,
384
- name: str,
385
- description: str,
386
- definition: dict[str, Any],
387
- created_by: str = None,
388
- ) -> Workflow:
389
- """Create a new workflow"""
390
- workflow = Workflow(
391
- tenant_id=tenant_id,
392
- name=name,
393
- description=description,
394
- definition=definition,
395
- created_by=created_by,
396
- )
397
- self.session.add(workflow)
398
- self.session.commit()
399
-
400
- # Create initial version
401
- self.create_version(workflow.id, 1, definition, "Initial version", created_by)
402
-
403
- return workflow
404
-
405
- def update(
406
- self, workflow_id: str, updates: dict[str, Any], updated_by: str = None
407
- ) -> Workflow:
408
- """Update a workflow"""
409
- workflow = self.session.query(Workflow).filter_by(id=workflow_id).first()
410
- if not workflow:
411
- raise ValueError(f"Workflow {workflow_id} not found")
412
-
413
- # Update fields
414
- for key, value in updates.items():
415
- if hasattr(workflow, key):
416
- setattr(workflow, key, value)
417
-
418
- # If definition changed, create new version
419
- if "definition" in updates:
420
- workflow.version += 1
421
- self.create_version(
422
- workflow_id,
423
- workflow.version,
424
- updates["definition"],
425
- updates.get("change_message", "Updated workflow"),
426
- updated_by,
427
- )
428
-
429
- self.session.commit()
430
- return workflow
431
-
432
- def create_version(
433
- self,
434
- workflow_id: str,
435
- version: int,
436
- definition: dict[str, Any],
437
- change_message: str,
438
- created_by: str = None,
439
- ):
440
- """Create a workflow version"""
441
- version_record = WorkflowVersion(
442
- workflow_id=workflow_id,
443
- version=version,
444
- definition=definition,
445
- change_message=change_message,
446
- created_by=created_by,
447
- )
448
- self.session.add(version_record)
449
- self.session.commit()
450
-
451
- def get(self, workflow_id: str) -> Workflow | None:
452
- """Get a workflow by ID"""
453
- return self.session.query(Workflow).filter_by(id=workflow_id).first()
454
-
455
- def list(self, tenant_id: str, limit: int = 100, offset: int = 0) -> list[Workflow]:
456
- """List workflows for a tenant"""
457
- return (
458
- self.session.query(Workflow)
459
- .filter_by(tenant_id=tenant_id)
460
- .order_by(Workflow.created_at.desc())
461
- .limit(limit)
462
- .offset(offset)
463
- .all()
464
- )
465
-
466
- def delete(self, workflow_id: str):
467
- """Delete a workflow"""
468
- workflow = self.get(workflow_id)
469
- if workflow:
470
- self.session.delete(workflow)
471
- self.session.commit()
472
-
473
-
474
- class CustomNodeRepository:
475
- """Repository for custom node operations"""
476
-
477
- def __init__(self, session: Session):
478
- self.session = session
479
-
480
- def create(self, tenant_id: str, node_data: dict[str, Any]) -> CustomNode:
481
- """Create a custom node"""
482
- node = CustomNode(tenant_id=tenant_id, **node_data)
483
- self.session.add(node)
484
- self.session.commit()
485
- return node
486
-
487
- def update(self, node_id: str, updates: dict[str, Any]) -> CustomNode:
488
- """Update a custom node"""
489
- node = self.session.query(CustomNode).filter_by(id=node_id).first()
490
- if not node:
491
- raise ValueError(f"Custom node {node_id} not found")
492
-
493
- for key, value in updates.items():
494
- if hasattr(node, key):
495
- setattr(node, key, value)
496
-
497
- self.session.commit()
498
- return node
499
-
500
- def list(self, tenant_id: str) -> list[CustomNode]:
501
- """List custom nodes for a tenant"""
502
- return (
503
- self.session.query(CustomNode)
504
- .filter_by(tenant_id=tenant_id)
505
- .order_by(CustomNode.category, CustomNode.name)
506
- .all()
507
- )
508
-
509
- def get(self, node_id: str) -> CustomNode | None:
510
- """Get a custom node by ID"""
511
- return self.session.query(CustomNode).filter_by(id=node_id).first()
512
-
513
- def delete(self, node_id: str):
514
- """Delete a custom node"""
515
- node = self.get(node_id)
516
- if node:
517
- self.session.delete(node)
518
- self.session.commit()
519
-
520
-
521
- class ExecutionRepository:
522
- """Repository for execution operations"""
523
-
524
- def __init__(self, session: Session):
525
- self.session = session
526
-
527
- def create(
528
- self, workflow_id: str, tenant_id: str, parameters: dict[str, Any] = None
529
- ) -> WorkflowExecution:
530
- """Create an execution record"""
531
- execution = WorkflowExecution(
532
- workflow_id=workflow_id,
533
- tenant_id=tenant_id,
534
- status="pending",
535
- parameters=parameters,
536
- started_at=datetime.now(UTC),
537
- )
538
- self.session.add(execution)
539
- self.session.commit()
540
- return execution
541
-
542
- def update_status(
543
- self,
544
- execution_id: str,
545
- status: str,
546
- result: dict[str, Any] = None,
547
- error: str = None,
548
- ):
549
- """Update execution status"""
550
- execution = (
551
- self.session.query(WorkflowExecution).filter_by(id=execution_id).first()
552
- )
553
- if not execution:
554
- raise ValueError(f"Execution {execution_id} not found")
555
-
556
- execution.status = status
557
- if result is not None:
558
- execution.result = result
559
- if error is not None:
560
- execution.error = error
561
-
562
- if status in ["completed", "failed"]:
563
- execution.completed_at = datetime.now(UTC)
564
- if execution.started_at:
565
- execution.execution_time_ms = int(
566
- (execution.completed_at - execution.started_at).total_seconds()
567
- * 1000
568
- )
569
-
570
- self.session.commit()
571
-
572
- def get(self, execution_id: str) -> WorkflowExecution | None:
573
- """Get execution by ID"""
574
- return self.session.query(WorkflowExecution).filter_by(id=execution_id).first()
575
-
576
- def list_for_workflow(
577
- self, workflow_id: str, limit: int = 50
578
- ) -> list[WorkflowExecution]:
579
- """List executions for a workflow"""
580
- return (
581
- self.session.query(WorkflowExecution)
582
- .filter_by(workflow_id=workflow_id)
583
- .order_by(WorkflowExecution.started_at.desc())
584
- .limit(limit)
585
- .all()
586
- )
587
-
588
-
589
- # Database initialization
590
- def init_database(db_path: str = None) -> tuple[sessionmaker, Engine]:
591
- """Initialize the database"""
592
- if db_path is None:
593
- db_path = Path.home() / ".kailash" / "studio.db"
594
-
595
- db_path = Path(db_path)
596
- db_path.parent.mkdir(parents=True, exist_ok=True)
597
-
598
- engine = create_engine(f"sqlite:///{db_path}", echo=False)
599
- Base.metadata.create_all(engine)
600
-
601
- SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
602
-
603
- return SessionLocal, engine
604
-
605
-
606
- # Context manager for database sessions
607
-
608
-
609
- @contextmanager
610
- def get_db_session(SessionLocal):
611
- """Provide a transactional scope for database operations"""
612
- session = SessionLocal()
613
- try:
614
- yield session
615
- session.commit()
616
- except Exception:
617
- session.rollback()
618
- raise
619
- finally:
620
- session.close()
436
+ class MiddlewareSessionModel(Base):
437
+ """Middleware-specific session tracking"""
438
+
439
+ __tablename__ = "middleware_sessions"
440
+
441
+ id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
442
+ tenant_id = Column(String(36), nullable=False, index=True)
443
+ user_id = Column(String(36), nullable=False, index=True)
444
+
445
+ # Session details
446
+ session_type = Column(String(50), nullable=False) # agent_ui, api, websocket, mcp
447
+ status = Column(String(20), default="active") # active, inactive, expired
448
+
449
+ # Session data
450
+ session_metadata = Column(JSON) # Session-specific metadata
451
+ preferences = Column(JSON) # User preferences for this session
452
+ context = Column(JSON) # Session context data
453
+
454
+ # Connection details
455
+ connection_id = Column(String(255)) # WebSocket/API connection ID
456
+ ip_address = Column(String(50))
457
+ user_agent = Column(String(255))
458
+
459
+ # Timestamps
460
+ created_at = Column(DateTime, default=func.now())
461
+ last_activity = Column(DateTime, default=func.now())
462
+ expires_at = Column(DateTime)
463
+
464
+ __table_args__ = (
465
+ Index("idx_session_tenant_user", "tenant_id", "user_id"),
466
+ Index("idx_session_status", "status"),
467
+ Index("idx_session_type", "session_type"),
468
+ Index("idx_session_activity", "last_activity"),
469
+ )
470
+
471
+
472
+ class MiddlewareEventModel(Base):
473
+ """Middleware event logging for audit and replay"""
474
+
475
+ __tablename__ = "middleware_events"
476
+
477
+ id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
478
+ tenant_id = Column(String(36), nullable=False, index=True)
479
+
480
+ # Event details
481
+ event_type = Column(String(100), nullable=False, index=True)
482
+ event_source = Column(
483
+ String(50), nullable=False
484
+ ) # agent_ui, api_gateway, realtime, etc.
485
+
486
+ # Event data
487
+ data = Column(JSON, nullable=False)
488
+ context = Column(JSON) # Additional context
489
+
490
+ # Associated entities
491
+ session_id = Column(String(36), nullable=True, index=True)
492
+ user_id = Column(String(36), nullable=True, index=True)
493
+ workflow_id = Column(String(36), nullable=True, index=True)
494
+ execution_id = Column(String(36), nullable=True, index=True)
495
+
496
+ # Event metadata
497
+ correlation_id = Column(String(36)) # For tracing related events
498
+ sequence_number = Column(Integer) # For ordering within correlation
499
+
500
+ # Processing status
501
+ processed = Column(Boolean, default=False)
502
+ processed_at = Column(DateTime)
503
+ error_message = Column(Text)
504
+
505
+ # Timestamp
506
+ timestamp = Column(DateTime, default=func.now(), index=True)
507
+
508
+ __table_args__ = (
509
+ Index("idx_event_type_time", "event_type", "timestamp"),
510
+ Index("idx_event_correlation", "correlation_id", "sequence_number"),
511
+ Index("idx_event_processed", "processed"),
512
+ )