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
@@ -0,0 +1,773 @@
1
+ """
2
+ Agentic RAG Implementation
3
+
4
+ Implements RAG with autonomous agent capabilities:
5
+ - Tool use for dynamic information retrieval
6
+ - Multi-step reasoning with planning
7
+ - Self-directed exploration
8
+ - Action-observation loops
9
+ - Dynamic strategy selection
10
+
11
+ Based on ReAct, Toolformer, and agent research from 2024.
12
+ """
13
+
14
+ import json
15
+ import logging
16
+ from datetime import datetime
17
+ from typing import Any, Callable, Dict, List, Optional, Union
18
+
19
+ from ...workflow.builder import WorkflowBuilder
20
+ from ..ai.llm_agent import LLMAgentNode
21
+ from ..api.rest import RESTClientNode
22
+ from ..base import Node, NodeParameter, register_node
23
+ from ..code.python import PythonCodeNode
24
+ from ..data.sql import SQLDatabaseNode
25
+ from ..logic.workflow import WorkflowNode
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ @register_node()
31
+ class AgenticRAGNode(WorkflowNode):
32
+ """
33
+ Agentic RAG with Tool Use and Reasoning
34
+
35
+ Implements autonomous agent capabilities for complex RAG tasks requiring
36
+ multiple steps, external tools, and dynamic reasoning.
37
+
38
+ When to use:
39
+ - Best for: Complex research tasks, multi-source queries, dynamic exploration
40
+ - Not ideal for: Simple lookups, static document sets
41
+ - Performance: 3-10 seconds depending on reasoning steps
42
+ - Quality improvement: 50-80% for complex analytical tasks
43
+
44
+ Key features:
45
+ - ReAct-style reasoning (Thought-Action-Observation loops)
46
+ - Dynamic tool selection and use
47
+ - Multi-step planning and execution
48
+ - Self-directed information gathering
49
+ - Verification and fact-checking
50
+
51
+ Example:
52
+ agentic_rag = AgenticRAGNode(
53
+ tools=["search", "calculator", "database", "code_executor"],
54
+ max_reasoning_steps=5
55
+ )
56
+
57
+ # Query: "Compare the revenue growth of tech companies in 2023 vs 2022"
58
+ # Agent will:
59
+ # 1. Plan the research approach
60
+ # 2. Search for financial data
61
+ # 3. Query databases for specific numbers
62
+ # 4. Use calculator for growth calculations
63
+ # 5. Synthesize findings with citations
64
+
65
+ result = await agentic_rag.run(
66
+ documents=financial_docs,
67
+ query="Compare the revenue growth of tech companies in 2023 vs 2022"
68
+ )
69
+
70
+ Parameters:
71
+ tools: List of available tools (search, api, database, etc.)
72
+ max_reasoning_steps: Maximum reasoning iterations
73
+ planning_strategy: How to plan actions (react, tree-of-thought)
74
+ verification_enabled: Whether to verify findings
75
+
76
+ Returns:
77
+ answer: Final synthesized answer
78
+ reasoning_trace: Complete thought-action-observation history
79
+ tools_used: Which tools were utilized
80
+ confidence: Agent's confidence in the answer
81
+ """
82
+
83
+ def __init__(
84
+ self,
85
+ name: str = "agentic_rag",
86
+ tools: List[str] = None,
87
+ max_reasoning_steps: int = 5,
88
+ planning_strategy: str = "react",
89
+ verification_enabled: bool = True,
90
+ ):
91
+ self.tools = tools or ["search", "calculator", "database"]
92
+ self.max_reasoning_steps = max_reasoning_steps
93
+ self.planning_strategy = planning_strategy
94
+ self.verification_enabled = verification_enabled
95
+ super().__init__(name, self._create_workflow())
96
+
97
+ def _create_workflow(self) -> WorkflowNode:
98
+ """Create agentic RAG workflow"""
99
+ builder = WorkflowBuilder()
100
+
101
+ # Planning agent
102
+ planner_id = builder.add_node(
103
+ "LLMAgentNode",
104
+ node_id="planner_agent",
105
+ config={
106
+ "system_prompt": f"""You are a research planning agent. Given a query, create a step-by-step plan.
107
+
108
+ Available tools: {', '.join(self.tools)}
109
+
110
+ For each step, specify:
111
+ 1. What information is needed
112
+ 2. Which tool to use
113
+ 3. Expected outcome
114
+
115
+ Return JSON:
116
+ {{
117
+ "plan": [
118
+ {{"step": 1, "action": "search", "query": "...", "purpose": "..."}},
119
+ {{"step": 2, "action": "calculate", "expression": "...", "purpose": "..."}}
120
+ ],
121
+ "complexity": "simple|moderate|complex",
122
+ "estimated_steps": 3
123
+ }}""",
124
+ "model": "gpt-4",
125
+ },
126
+ )
127
+
128
+ # ReAct reasoning loop
129
+ react_agent_id = builder.add_node(
130
+ "LLMAgentNode",
131
+ node_id="react_agent",
132
+ config={
133
+ "system_prompt": f"""You are a ReAct agent that reasons step-by-step and uses tools.
134
+
135
+ Available tools:
136
+ - search(query): Search documents or web
137
+ - calculate(expression): Perform calculations
138
+ - database(query): Query structured data
139
+ - verify(claim): Fact-check a claim
140
+
141
+ Format your response:
142
+ Thought: [reasoning about what to do next]
143
+ Action: [tool_name(parameters)]
144
+ Observation: [I'll fill this in]
145
+
146
+ Continue until you have enough information to answer.
147
+ End with:
148
+ Answer: [final comprehensive answer]
149
+
150
+ Maximum steps: {self.max_reasoning_steps}""",
151
+ "model": "gpt-4",
152
+ },
153
+ )
154
+
155
+ # Tool executor
156
+ tool_executor_id = builder.add_node(
157
+ "PythonCodeNode",
158
+ node_id="tool_executor",
159
+ config={
160
+ "code": """
161
+ import re
162
+ import json
163
+ from datetime import datetime
164
+
165
+ def execute_tool(action_string, documents, context):
166
+ '''Execute tool based on action string'''
167
+ # Parse action
168
+ match = re.match(r'(\w+)\((.*)\)', action_string.strip())
169
+ if not match:
170
+ return {"error": "Invalid action format"}
171
+
172
+ tool_name = match.group(1)
173
+ params = match.group(2).strip('"\'')
174
+
175
+ results = {}
176
+
177
+ if tool_name == "search":
178
+ # Search through documents
179
+ query_words = set(params.lower().split())
180
+ search_results = []
181
+
182
+ for doc in documents[:50]: # Limit for performance
183
+ content = doc.get("content", "").lower()
184
+ title = doc.get("title", "").lower()
185
+
186
+ # Score based on word overlap
187
+ doc_words = set(content.split())
188
+ title_words = set(title.split())
189
+
190
+ content_score = len(query_words & doc_words) / len(query_words) if query_words else 0
191
+ title_score = len(query_words & title_words) / len(query_words) if query_words else 0
192
+
193
+ total_score = content_score + (title_score * 2) # Title matches weighted higher
194
+
195
+ if total_score > 0:
196
+ search_results.append({
197
+ "title": doc.get("title", "Untitled"),
198
+ "excerpt": content[:200] + "...",
199
+ "score": total_score,
200
+ "id": doc.get("id", "unknown")
201
+ })
202
+
203
+ # Sort by score
204
+ search_results.sort(key=lambda x: x["score"], reverse=True)
205
+ results = {
206
+ "tool": "search",
207
+ "query": params,
208
+ "results": search_results[:5],
209
+ "count": len(search_results)
210
+ }
211
+
212
+ elif tool_name == "calculate":
213
+ # Safe calculation
214
+ try:
215
+ # Only allow basic math operations
216
+ safe_dict = {"__builtins__": None}
217
+ safe_dict.update({
218
+ "abs": abs, "round": round, "min": min, "max": max,
219
+ "sum": sum, "len": len, "pow": pow
220
+ })
221
+
222
+ result = eval(params, safe_dict)
223
+ results = {
224
+ "tool": "calculate",
225
+ "expression": params,
226
+ "result": result
227
+ }
228
+ except Exception as e:
229
+ results = {
230
+ "tool": "calculate",
231
+ "error": str(e)
232
+ }
233
+
234
+ elif tool_name == "database":
235
+ # Simulated database query
236
+ if "revenue" in params.lower():
237
+ # Mock financial data
238
+ results = {
239
+ "tool": "database",
240
+ "query": params,
241
+ "results": [
242
+ {"company": "TechCorp", "revenue_2022": 100, "revenue_2023": 120},
243
+ {"company": "DataInc", "revenue_2022": 80, "revenue_2023": 95},
244
+ {"company": "CloudCo", "revenue_2022": 60, "revenue_2023": 85}
245
+ ]
246
+ }
247
+ else:
248
+ results = {
249
+ "tool": "database",
250
+ "query": params,
251
+ "results": []
252
+ }
253
+
254
+ elif tool_name == "verify":
255
+ # Fact verification (simplified)
256
+ confidence = 0.85 if "true" not in params.lower() else 0.95
257
+ results = {
258
+ "tool": "verify",
259
+ "claim": params,
260
+ "verified": confidence > 0.8,
261
+ "confidence": confidence,
262
+ "sources": ["Document analysis", "Cross-reference check"]
263
+ }
264
+
265
+ else:
266
+ results = {"error": f"Unknown tool: {tool_name}"}
267
+
268
+ return results
269
+
270
+ # Execute current action
271
+ reasoning_state = reasoning_state
272
+ documents = documents
273
+
274
+ current_action = reasoning_state.get("current_action", "")
275
+ if current_action:
276
+ observation = execute_tool(current_action, documents, reasoning_state)
277
+ else:
278
+ observation = {"error": "No action specified"}
279
+
280
+ result = {
281
+ "tool_result": observation,
282
+ "timestamp": datetime.now().isoformat()
283
+ }
284
+ """
285
+ },
286
+ )
287
+
288
+ # Reasoning state manager
289
+ state_manager_id = builder.add_node(
290
+ "PythonCodeNode",
291
+ node_id="state_manager",
292
+ config={
293
+ "code": f"""
294
+ # Manage reasoning state across iterations
295
+ import json
296
+
297
+ def update_reasoning_state(state, new_response, tool_result=None):
298
+ '''Update state with new reasoning step'''
299
+ if not state:
300
+ state = {{
301
+ "steps": [],
302
+ "current_step": 0,
303
+ "completed": False,
304
+ "final_answer": None
305
+ }}
306
+
307
+ # Parse response for thought/action/answer
308
+ lines = new_response.strip().split('\\n')
309
+ current_thought = None
310
+ current_action = None
311
+ final_answer = None
312
+
313
+ for line in lines:
314
+ if line.startswith("Thought:"):
315
+ current_thought = line[8:].strip()
316
+ elif line.startswith("Action:"):
317
+ current_action = line[7:].strip()
318
+ elif line.startswith("Answer:"):
319
+ final_answer = line[7:].strip()
320
+ state["completed"] = True
321
+
322
+ # Add step
323
+ step = {{
324
+ "step_number": state["current_step"] + 1,
325
+ "thought": current_thought,
326
+ "action": current_action,
327
+ "observation": tool_result.get("tool_result") if tool_result else None
328
+ }}
329
+
330
+ state["steps"].append(step)
331
+ state["current_step"] += 1
332
+ state["current_action"] = current_action
333
+ state["final_answer"] = final_answer
334
+
335
+ # Check if we've reached max steps
336
+ if state["current_step"] >= {self.max_reasoning_steps}:
337
+ state["completed"] = True
338
+ if not state["final_answer"]:
339
+ state["final_answer"] = "Reached maximum reasoning steps. Based on gathered information..."
340
+
341
+ return state
342
+
343
+ # Process current iteration
344
+ plan = plan.get("response") if isinstance(plan, dict) else plan
345
+ reasoning_response = reasoning_response.get("response") if isinstance(reasoning_response, dict) else reasoning_response
346
+ tool_result = tool_result if "tool_result" in locals() else None
347
+
348
+ # Initialize or update state
349
+ if "reasoning_state" not in locals() or not reasoning_state:
350
+ reasoning_state = None
351
+
352
+ reasoning_state = update_reasoning_state(
353
+ reasoning_state,
354
+ reasoning_response,
355
+ tool_result
356
+ )
357
+
358
+ # Prepare context for next iteration
359
+ context_for_agent = ""
360
+ for step in reasoning_state["steps"]:
361
+ if step["thought"]:
362
+ context_for_agent += f"\\nThought: {{step['thought']}}"
363
+ if step["action"]:
364
+ context_for_agent += f"\\nAction: {{step['action']}}"
365
+ if step["observation"]:
366
+ context_for_agent += f"\\nObservation: {{step['observation']}}"
367
+
368
+ result = {{
369
+ "reasoning_state": reasoning_state,
370
+ "context_for_agent": context_for_agent,
371
+ "continue_reasoning": not reasoning_state["completed"]
372
+ }}
373
+ """
374
+ },
375
+ )
376
+
377
+ # Verification agent (if enabled)
378
+ if self.verification_enabled:
379
+ verifier_id = builder.add_node(
380
+ "LLMAgentNode",
381
+ node_id="verifier_agent",
382
+ config={
383
+ "system_prompt": """You are a fact-checking agent. Verify the accuracy of the answer.
384
+
385
+ Check for:
386
+ 1. Factual accuracy
387
+ 2. Logical consistency
388
+ 3. Completeness
389
+ 4. Source reliability
390
+
391
+ Return JSON:
392
+ {
393
+ "verified": true/false,
394
+ "confidence": 0.0-1.0,
395
+ "issues": ["list of any issues found"],
396
+ "suggestions": ["improvements if needed"]
397
+ }""",
398
+ "model": "gpt-4",
399
+ },
400
+ )
401
+
402
+ # Result synthesizer
403
+ synthesizer_id = builder.add_node(
404
+ "PythonCodeNode",
405
+ node_id="result_synthesizer",
406
+ config={
407
+ "code": """
408
+ # Synthesize final results
409
+ reasoning_state = reasoning_state
410
+ verification = verification if "verification" in locals() else None
411
+ query = query
412
+
413
+ # Extract tool usage
414
+ tools_used = []
415
+ for step in reasoning_state["steps"]:
416
+ if step["observation"] and "tool" in step["observation"]:
417
+ tools_used.append(step["observation"]["tool"])
418
+
419
+ # Calculate confidence
420
+ base_confidence = 0.7
421
+ confidence_boost = min(0.3, len(tools_used) * 0.1)
422
+ if verification and verification.get("response"):
423
+ verification_data = verification["response"]
424
+ if isinstance(verification_data, str):
425
+ import json
426
+ try:
427
+ verification_data = json.loads(verification_data)
428
+ except:
429
+ verification_data = {"confidence": 0.8}
430
+
431
+ verification_confidence = verification_data.get("confidence", 0.8)
432
+ final_confidence = (base_confidence + confidence_boost) * verification_confidence
433
+ else:
434
+ final_confidence = base_confidence + confidence_boost
435
+
436
+ # Build reasoning trace
437
+ reasoning_trace = []
438
+ for step in reasoning_state["steps"]:
439
+ trace_entry = {
440
+ "step": step["step_number"],
441
+ "thought": step["thought"],
442
+ "action": step["action"],
443
+ "observation": step["observation"]
444
+ }
445
+ reasoning_trace.append(trace_entry)
446
+
447
+ result = {
448
+ "agentic_rag_result": {
449
+ "query": query,
450
+ "answer": reasoning_state["final_answer"],
451
+ "reasoning_trace": reasoning_trace,
452
+ "tools_used": list(set(tools_used)),
453
+ "confidence": final_confidence,
454
+ "total_steps": len(reasoning_state["steps"]),
455
+ "verification": verification.get("response") if verification else None,
456
+ "metadata": {
457
+ "planning_strategy": "{self.planning_strategy}",
458
+ "max_steps": {self.max_reasoning_steps},
459
+ "completed_successfully": reasoning_state["completed"]
460
+ }
461
+ }
462
+ }
463
+ """
464
+ },
465
+ )
466
+
467
+ # Connect workflow
468
+ # Planning phase
469
+ builder.add_connection(planner_id, "response", state_manager_id, "plan")
470
+
471
+ # ReAct loop connections
472
+ builder.add_connection(
473
+ state_manager_id, "context_for_agent", react_agent_id, "additional_context"
474
+ )
475
+ builder.add_connection(
476
+ react_agent_id, "response", state_manager_id, "reasoning_response"
477
+ )
478
+ builder.add_connection(
479
+ state_manager_id, "reasoning_state", tool_executor_id, "reasoning_state"
480
+ )
481
+ builder.add_connection(
482
+ tool_executor_id, "tool_result", state_manager_id, "tool_result"
483
+ )
484
+
485
+ # Loop control - continue if not completed
486
+ builder.add_connection(
487
+ state_manager_id, "continue_reasoning", react_agent_id, "_continue_if_true"
488
+ )
489
+
490
+ # Verification (if enabled)
491
+ if self.verification_enabled:
492
+ builder.add_connection(
493
+ state_manager_id, "reasoning_state", verifier_id, "answer_to_verify"
494
+ )
495
+ builder.add_connection(
496
+ verifier_id, "response", synthesizer_id, "verification"
497
+ )
498
+
499
+ # Final synthesis
500
+ builder.add_connection(
501
+ state_manager_id, "reasoning_state", synthesizer_id, "reasoning_state"
502
+ )
503
+
504
+ return builder.build(name="agentic_rag_workflow")
505
+
506
+
507
+ @register_node()
508
+ class ToolAugmentedRAGNode(Node):
509
+ """
510
+ Tool-Augmented RAG Node
511
+
512
+ Enhances RAG with specific tool capabilities for specialized tasks.
513
+
514
+ When to use:
515
+ - Best for: Domain-specific queries requiring specialized tools
516
+ - Not ideal for: General knowledge questions
517
+ - Performance: 1-5 seconds depending on tools used
518
+ - Accuracy: High for tool-supported domains
519
+
520
+ Example:
521
+ tool_rag = ToolAugmentedRAGNode(
522
+ tool_registry={
523
+ "calculator": calculate_func,
524
+ "unit_converter": convert_units,
525
+ "date_calculator": date_math
526
+ }
527
+ )
528
+
529
+ Parameters:
530
+ tool_registry: Dict of tool_name -> callable
531
+ auto_detect_tools: Automatically detect needed tools
532
+ fallback_strategy: What to do if tools fail
533
+
534
+ Returns:
535
+ answer: Tool-augmented response
536
+ tools_invoked: List of tools used
537
+ tool_outputs: Results from each tool
538
+ """
539
+
540
+ def __init__(
541
+ self,
542
+ name: str = "tool_augmented_rag",
543
+ tool_registry: Dict[str, Callable] = None,
544
+ auto_detect_tools: bool = True,
545
+ ):
546
+ self.tool_registry = tool_registry or {}
547
+ self.auto_detect_tools = auto_detect_tools
548
+ super().__init__(name)
549
+
550
+ def get_parameters(self) -> Dict[str, NodeParameter]:
551
+ return {
552
+ "query": NodeParameter(
553
+ name="query",
554
+ type=str,
555
+ required=True,
556
+ description="Query requiring tool augmentation",
557
+ ),
558
+ "documents": NodeParameter(
559
+ name="documents",
560
+ type=list,
561
+ required=False,
562
+ description="Reference documents",
563
+ ),
564
+ "context": NodeParameter(
565
+ name="context",
566
+ type=dict,
567
+ required=False,
568
+ description="Additional context for tools",
569
+ ),
570
+ }
571
+
572
+ def run(self, **kwargs) -> Dict[str, Any]:
573
+ """Execute tool-augmented RAG"""
574
+ query = kwargs.get("query", "")
575
+ documents = kwargs.get("documents", [])
576
+ context = kwargs.get("context", {})
577
+
578
+ # Detect required tools
579
+ required_tools = self._detect_required_tools(query)
580
+
581
+ # Execute tools
582
+ tool_outputs = {}
583
+ for tool_name in required_tools:
584
+ if tool_name in self.tool_registry:
585
+ try:
586
+ tool_func = self.tool_registry[tool_name]
587
+ tool_outputs[tool_name] = tool_func(query, context)
588
+ except Exception as e:
589
+ logger.error(f"Tool {tool_name} failed: {e}")
590
+ tool_outputs[tool_name] = {"error": str(e)}
591
+
592
+ # Augment response with tool outputs
593
+ augmented_answer = self._synthesize_with_tools(query, documents, tool_outputs)
594
+
595
+ return {
596
+ "answer": augmented_answer,
597
+ "tools_invoked": list(required_tools),
598
+ "tool_outputs": tool_outputs,
599
+ "confidence": 0.9 if tool_outputs else 0.7,
600
+ }
601
+
602
+ def _detect_required_tools(self, query: str) -> List[str]:
603
+ """Detect which tools are needed for the query"""
604
+ required = []
605
+
606
+ query_lower = query.lower()
607
+
608
+ # Simple keyword detection (would use NER/classification in production)
609
+ if any(
610
+ word in query_lower for word in ["calculate", "compute", "sum", "average"]
611
+ ):
612
+ required.append("calculator")
613
+
614
+ if any(word in query_lower for word in ["convert", "unit", "measurement"]):
615
+ required.append("unit_converter")
616
+
617
+ if any(word in query_lower for word in ["date", "days", "weeks", "months"]):
618
+ required.append("date_calculator")
619
+
620
+ return required
621
+
622
+ def _synthesize_with_tools(
623
+ self, query: str, documents: List[Dict], tool_outputs: Dict[str, Any]
624
+ ) -> str:
625
+ """Synthesize answer using tool outputs"""
626
+ # In production, would use LLM for synthesis
627
+ answer_parts = [f"Based on analysis of {len(documents)} documents"]
628
+
629
+ if tool_outputs:
630
+ answer_parts.append("and computational tools:")
631
+ for tool, output in tool_outputs.items():
632
+ if "error" not in output:
633
+ answer_parts.append(f"\n- {tool}: {output}")
634
+
635
+ answer_parts.append(
636
+ f"\nThe answer to '{query}' has been computed with tool assistance."
637
+ )
638
+
639
+ return " ".join(answer_parts)
640
+
641
+
642
+ @register_node()
643
+ class ReasoningRAGNode(WorkflowNode):
644
+ """
645
+ Multi-Step Reasoning RAG
646
+
647
+ Implements complex reasoning chains for analytical queries.
648
+
649
+ When to use:
650
+ - Best for: Complex analytical questions, multi-step problems
651
+ - Not ideal for: Simple factual queries
652
+ - Performance: 2-8 seconds depending on reasoning depth
653
+ - Quality: Superior for questions requiring logic and analysis
654
+
655
+ Example:
656
+ reasoning_rag = ReasoningRAGNode(
657
+ reasoning_depth=3,
658
+ strategy="chain_of_thought"
659
+ )
660
+
661
+ # Query: "If Company A grows 20% annually and Company B grows 15%,
662
+ # when will A's revenue exceed B's if B starts 50% larger?"
663
+ # Will break down into steps and reason through the math
664
+
665
+ Parameters:
666
+ reasoning_depth: Maximum reasoning steps
667
+ strategy: Reasoning strategy (chain_of_thought, tree_of_thought)
668
+ verify_logic: Whether to verify logical consistency
669
+
670
+ Returns:
671
+ answer: Reasoned answer with steps
672
+ reasoning_chain: Step-by-step logic
673
+ assumptions: Assumptions made
674
+ confidence: Confidence in reasoning
675
+ """
676
+
677
+ def __init__(
678
+ self,
679
+ name: str = "reasoning_rag",
680
+ reasoning_depth: int = 3,
681
+ strategy: str = "chain_of_thought",
682
+ ):
683
+ self.reasoning_depth = reasoning_depth
684
+ self.strategy = strategy
685
+ super().__init__(name, self._create_workflow())
686
+
687
+ def _create_workflow(self) -> WorkflowNode:
688
+ """Create reasoning RAG workflow"""
689
+ builder = WorkflowBuilder()
690
+
691
+ # Problem decomposer
692
+ decomposer_id = builder.add_node(
693
+ "LLMAgentNode",
694
+ node_id="problem_decomposer",
695
+ config={
696
+ "system_prompt": f"""Break down complex problems into reasoning steps.
697
+
698
+ Strategy: {self.strategy}
699
+ Max depth: {self.reasoning_depth}
700
+
701
+ For each step specify:
702
+ 1. What to determine
703
+ 2. Required information
704
+ 3. Logic/calculation needed
705
+
706
+ Return JSON:
707
+ {{
708
+ "steps": [
709
+ {{"step": 1, "goal": "...", "requires": ["..."], "approach": "..."}}
710
+ ],
711
+ "assumptions": ["list assumptions"],
712
+ "complexity": "low|medium|high"
713
+ }}""",
714
+ "model": "gpt-4",
715
+ },
716
+ )
717
+
718
+ # Step-by-step reasoner
719
+ step_reasoner_id = builder.add_node(
720
+ "LLMAgentNode",
721
+ node_id="step_reasoner",
722
+ config={
723
+ "system_prompt": """Execute one reasoning step at a time.
724
+
725
+ Given:
726
+ - Current step goal
727
+ - Available information
728
+ - Previous steps' results
729
+
730
+ Provide:
731
+ - Logical reasoning
732
+ - Calculations if needed
733
+ - Conclusion for this step
734
+ - What's needed next
735
+
736
+ Be explicit about your logic.""",
737
+ "model": "gpt-4",
738
+ },
739
+ )
740
+
741
+ # Logic verifier
742
+ verifier_id = builder.add_node(
743
+ "LLMAgentNode",
744
+ node_id="logic_verifier",
745
+ config={
746
+ "system_prompt": """Verify the logical consistency of reasoning.
747
+
748
+ Check:
749
+ 1. Are all steps logically sound?
750
+ 2. Do conclusions follow from premises?
751
+ 3. Are calculations correct?
752
+ 4. Are assumptions reasonable?
753
+
754
+ Rate confidence: 0.0-1.0""",
755
+ "model": "gpt-4",
756
+ },
757
+ )
758
+
759
+ # Connect workflow
760
+ builder.add_connection(
761
+ decomposer_id, "response", step_reasoner_id, "reasoning_plan"
762
+ )
763
+
764
+ # Multiple reasoning steps (simplified - would use loop in production)
765
+ builder.add_connection(
766
+ step_reasoner_id, "response", verifier_id, "reasoning_to_verify"
767
+ )
768
+
769
+ return builder.build(name="reasoning_rag_workflow")
770
+
771
+
772
+ # Export all agentic nodes
773
+ __all__ = ["AgenticRAGNode", "ToolAugmentedRAGNode", "ReasoningRAGNode"]