crca 1.4.0__py3-none-any.whl → 1.5.0__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 (306) hide show
  1. CRCA.py +172 -7
  2. MODEL_CARD.md +53 -0
  3. PKG-INFO +8 -2
  4. RELEASE_NOTES.md +17 -0
  5. STABILITY.md +19 -0
  6. architecture/hybrid/consistency_engine.py +362 -0
  7. architecture/hybrid/conversation_manager.py +421 -0
  8. architecture/hybrid/explanation_generator.py +452 -0
  9. architecture/hybrid/few_shot_learner.py +533 -0
  10. architecture/hybrid/graph_compressor.py +286 -0
  11. architecture/hybrid/hybrid_agent.py +4398 -0
  12. architecture/hybrid/language_compiler.py +623 -0
  13. architecture/hybrid/main,py +0 -0
  14. architecture/hybrid/reasoning_tracker.py +322 -0
  15. architecture/hybrid/self_verifier.py +524 -0
  16. architecture/hybrid/task_decomposer.py +567 -0
  17. architecture/hybrid/text_corrector.py +341 -0
  18. benchmark_results/crca_core_benchmarks.json +178 -0
  19. branches/crca_sd/crca_sd_realtime.py +6 -2
  20. branches/general_agent/__init__.py +102 -0
  21. branches/general_agent/general_agent.py +1400 -0
  22. branches/general_agent/personality.py +169 -0
  23. branches/general_agent/utils/__init__.py +19 -0
  24. branches/general_agent/utils/prompt_builder.py +170 -0
  25. {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/METADATA +8 -2
  26. {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/RECORD +303 -20
  27. crca_core/__init__.py +35 -0
  28. crca_core/benchmarks/__init__.py +14 -0
  29. crca_core/benchmarks/synthetic_scm.py +103 -0
  30. crca_core/core/__init__.py +23 -0
  31. crca_core/core/api.py +120 -0
  32. crca_core/core/estimate.py +208 -0
  33. crca_core/core/godclass.py +72 -0
  34. crca_core/core/intervention_design.py +174 -0
  35. crca_core/core/lifecycle.py +48 -0
  36. crca_core/discovery/__init__.py +9 -0
  37. crca_core/discovery/tabular.py +193 -0
  38. crca_core/identify/__init__.py +171 -0
  39. crca_core/identify/backdoor.py +39 -0
  40. crca_core/identify/frontdoor.py +48 -0
  41. crca_core/identify/graph.py +106 -0
  42. crca_core/identify/id_algorithm.py +43 -0
  43. crca_core/identify/iv.py +48 -0
  44. crca_core/models/__init__.py +67 -0
  45. crca_core/models/provenance.py +56 -0
  46. crca_core/models/refusal.py +39 -0
  47. crca_core/models/result.py +83 -0
  48. crca_core/models/spec.py +151 -0
  49. crca_core/models/validation.py +68 -0
  50. crca_core/scm/__init__.py +9 -0
  51. crca_core/scm/linear_gaussian.py +198 -0
  52. crca_core/timeseries/__init__.py +6 -0
  53. crca_core/timeseries/pcmci.py +181 -0
  54. crca_llm/__init__.py +12 -0
  55. crca_llm/client.py +85 -0
  56. crca_llm/coauthor.py +118 -0
  57. crca_llm/orchestrator.py +289 -0
  58. crca_llm/types.py +21 -0
  59. crca_reasoning/__init__.py +16 -0
  60. crca_reasoning/critique.py +54 -0
  61. crca_reasoning/godclass.py +206 -0
  62. crca_reasoning/memory.py +24 -0
  63. crca_reasoning/rationale.py +10 -0
  64. crca_reasoning/react_controller.py +81 -0
  65. crca_reasoning/tool_router.py +97 -0
  66. crca_reasoning/types.py +40 -0
  67. crca_sd/__init__.py +15 -0
  68. crca_sd/crca_sd_core.py +2 -0
  69. crca_sd/crca_sd_governance.py +2 -0
  70. crca_sd/crca_sd_mpc.py +2 -0
  71. crca_sd/crca_sd_realtime.py +2 -0
  72. crca_sd/crca_sd_tui.py +2 -0
  73. cuda-keyring_1.1-1_all.deb +0 -0
  74. cuda-keyring_1.1-1_all.deb.1 +0 -0
  75. docs/IMAGE_ANNOTATION_USAGE.md +539 -0
  76. docs/INSTALL_DEEPSPEED.md +125 -0
  77. docs/api/branches/crca-cg.md +19 -0
  78. docs/api/branches/crca-q.md +27 -0
  79. docs/api/branches/crca-sd.md +37 -0
  80. docs/api/branches/general-agent.md +24 -0
  81. docs/api/branches/overview.md +19 -0
  82. docs/api/crca/agent-methods.md +62 -0
  83. docs/api/crca/operations.md +79 -0
  84. docs/api/crca/overview.md +32 -0
  85. docs/api/image-annotation/engine.md +52 -0
  86. docs/api/image-annotation/overview.md +17 -0
  87. docs/api/schemas/annotation.md +34 -0
  88. docs/api/schemas/core-schemas.md +82 -0
  89. docs/api/schemas/overview.md +32 -0
  90. docs/api/schemas/policy.md +30 -0
  91. docs/api/utils/conversation.md +22 -0
  92. docs/api/utils/graph-reasoner.md +32 -0
  93. docs/api/utils/overview.md +21 -0
  94. docs/api/utils/router.md +19 -0
  95. docs/api/utils/utilities.md +97 -0
  96. docs/architecture/causal-graphs.md +41 -0
  97. docs/architecture/data-flow.md +29 -0
  98. docs/architecture/design-principles.md +33 -0
  99. docs/architecture/hybrid-agent/components.md +38 -0
  100. docs/architecture/hybrid-agent/consistency.md +26 -0
  101. docs/architecture/hybrid-agent/overview.md +44 -0
  102. docs/architecture/hybrid-agent/reasoning.md +22 -0
  103. docs/architecture/llm-integration.md +26 -0
  104. docs/architecture/modular-structure.md +37 -0
  105. docs/architecture/overview.md +69 -0
  106. docs/architecture/policy-engine-arch.md +29 -0
  107. docs/branches/crca-cg/corposwarm.md +39 -0
  108. docs/branches/crca-cg/esg-scoring.md +30 -0
  109. docs/branches/crca-cg/multi-agent.md +35 -0
  110. docs/branches/crca-cg/overview.md +40 -0
  111. docs/branches/crca-q/alternative-data.md +55 -0
  112. docs/branches/crca-q/architecture.md +71 -0
  113. docs/branches/crca-q/backtesting.md +45 -0
  114. docs/branches/crca-q/causal-engine.md +33 -0
  115. docs/branches/crca-q/execution.md +39 -0
  116. docs/branches/crca-q/market-data.md +60 -0
  117. docs/branches/crca-q/overview.md +58 -0
  118. docs/branches/crca-q/philosophy.md +60 -0
  119. docs/branches/crca-q/portfolio-optimization.md +66 -0
  120. docs/branches/crca-q/risk-management.md +102 -0
  121. docs/branches/crca-q/setup.md +65 -0
  122. docs/branches/crca-q/signal-generation.md +61 -0
  123. docs/branches/crca-q/signal-validation.md +43 -0
  124. docs/branches/crca-sd/core.md +84 -0
  125. docs/branches/crca-sd/governance.md +53 -0
  126. docs/branches/crca-sd/mpc-solver.md +65 -0
  127. docs/branches/crca-sd/overview.md +59 -0
  128. docs/branches/crca-sd/realtime.md +28 -0
  129. docs/branches/crca-sd/tui.md +20 -0
  130. docs/branches/general-agent/overview.md +37 -0
  131. docs/branches/general-agent/personality.md +36 -0
  132. docs/branches/general-agent/prompt-builder.md +30 -0
  133. docs/changelog/index.md +79 -0
  134. docs/contributing/code-style.md +69 -0
  135. docs/contributing/documentation.md +43 -0
  136. docs/contributing/overview.md +29 -0
  137. docs/contributing/testing.md +29 -0
  138. docs/core/crcagent/async-operations.md +65 -0
  139. docs/core/crcagent/automatic-extraction.md +107 -0
  140. docs/core/crcagent/batch-prediction.md +80 -0
  141. docs/core/crcagent/bayesian-inference.md +60 -0
  142. docs/core/crcagent/causal-graph.md +92 -0
  143. docs/core/crcagent/counterfactuals.md +96 -0
  144. docs/core/crcagent/deterministic-simulation.md +78 -0
  145. docs/core/crcagent/dual-mode-operation.md +82 -0
  146. docs/core/crcagent/initialization.md +88 -0
  147. docs/core/crcagent/optimization.md +65 -0
  148. docs/core/crcagent/overview.md +63 -0
  149. docs/core/crcagent/time-series.md +57 -0
  150. docs/core/schemas/annotation.md +30 -0
  151. docs/core/schemas/core-schemas.md +82 -0
  152. docs/core/schemas/overview.md +30 -0
  153. docs/core/schemas/policy.md +41 -0
  154. docs/core/templates/base-agent.md +31 -0
  155. docs/core/templates/feature-mixins.md +31 -0
  156. docs/core/templates/overview.md +29 -0
  157. docs/core/templates/templates-guide.md +75 -0
  158. docs/core/tools/mcp-client.md +34 -0
  159. docs/core/tools/overview.md +24 -0
  160. docs/core/utils/conversation.md +27 -0
  161. docs/core/utils/graph-reasoner.md +29 -0
  162. docs/core/utils/overview.md +27 -0
  163. docs/core/utils/router.md +27 -0
  164. docs/core/utils/utilities.md +97 -0
  165. docs/css/custom.css +84 -0
  166. docs/examples/basic-usage.md +57 -0
  167. docs/examples/general-agent/general-agent-examples.md +50 -0
  168. docs/examples/hybrid-agent/hybrid-agent-examples.md +56 -0
  169. docs/examples/image-annotation/image-annotation-examples.md +54 -0
  170. docs/examples/integration/integration-examples.md +58 -0
  171. docs/examples/overview.md +37 -0
  172. docs/examples/trading/trading-examples.md +46 -0
  173. docs/features/causal-reasoning/advanced-topics.md +101 -0
  174. docs/features/causal-reasoning/counterfactuals.md +43 -0
  175. docs/features/causal-reasoning/do-calculus.md +50 -0
  176. docs/features/causal-reasoning/overview.md +47 -0
  177. docs/features/causal-reasoning/structural-models.md +52 -0
  178. docs/features/hybrid-agent/advanced-components.md +55 -0
  179. docs/features/hybrid-agent/core-components.md +64 -0
  180. docs/features/hybrid-agent/overview.md +34 -0
  181. docs/features/image-annotation/engine.md +82 -0
  182. docs/features/image-annotation/features.md +113 -0
  183. docs/features/image-annotation/integration.md +75 -0
  184. docs/features/image-annotation/overview.md +53 -0
  185. docs/features/image-annotation/quickstart.md +73 -0
  186. docs/features/policy-engine/doctrine-ledger.md +105 -0
  187. docs/features/policy-engine/monitoring.md +44 -0
  188. docs/features/policy-engine/mpc-control.md +89 -0
  189. docs/features/policy-engine/overview.md +46 -0
  190. docs/getting-started/configuration.md +225 -0
  191. docs/getting-started/first-agent.md +164 -0
  192. docs/getting-started/installation.md +144 -0
  193. docs/getting-started/quickstart.md +137 -0
  194. docs/index.md +118 -0
  195. docs/js/mathjax.js +13 -0
  196. docs/lrm/discovery_proof_notes.md +25 -0
  197. docs/lrm/finetune_full.md +83 -0
  198. docs/lrm/math_appendix.md +120 -0
  199. docs/lrm/overview.md +32 -0
  200. docs/mkdocs.yml +238 -0
  201. docs/stylesheets/extra.css +21 -0
  202. docs_generated/crca_core/CounterfactualResult.md +12 -0
  203. docs_generated/crca_core/DiscoveryHypothesisResult.md +13 -0
  204. docs_generated/crca_core/DraftSpec.md +13 -0
  205. docs_generated/crca_core/EstimateResult.md +13 -0
  206. docs_generated/crca_core/IdentificationResult.md +17 -0
  207. docs_generated/crca_core/InterventionDesignResult.md +12 -0
  208. docs_generated/crca_core/LockedSpec.md +15 -0
  209. docs_generated/crca_core/RefusalResult.md +12 -0
  210. docs_generated/crca_core/ValidationReport.md +9 -0
  211. docs_generated/crca_core/index.md +13 -0
  212. examples/general_agent_example.py +277 -0
  213. examples/general_agent_quickstart.py +202 -0
  214. examples/general_agent_simple.py +92 -0
  215. examples/hybrid_agent_auto_extraction.py +84 -0
  216. examples/hybrid_agent_dictionary_demo.py +104 -0
  217. examples/hybrid_agent_enhanced.py +179 -0
  218. examples/hybrid_agent_general_knowledge.py +107 -0
  219. examples/image_annotation_quickstart.py +328 -0
  220. examples/test_hybrid_fixes.py +77 -0
  221. image_annotation/__init__.py +27 -0
  222. image_annotation/annotation_engine.py +2593 -0
  223. install_cuda_wsl2.sh +59 -0
  224. install_deepspeed.sh +56 -0
  225. install_deepspeed_simple.sh +87 -0
  226. mkdocs.yml +252 -0
  227. ollama/Modelfile +8 -0
  228. prompts/__init__.py +2 -1
  229. prompts/default_crca.py +9 -1
  230. prompts/general_agent.py +227 -0
  231. prompts/image_annotation.py +56 -0
  232. pyproject.toml +17 -2
  233. requirements-docs.txt +10 -0
  234. requirements.txt +21 -2
  235. schemas/__init__.py +26 -1
  236. schemas/annotation.py +222 -0
  237. schemas/conversation.py +193 -0
  238. schemas/hybrid.py +211 -0
  239. schemas/reasoning.py +276 -0
  240. schemas_export/crca_core/CounterfactualResult.schema.json +108 -0
  241. schemas_export/crca_core/DiscoveryHypothesisResult.schema.json +113 -0
  242. schemas_export/crca_core/DraftSpec.schema.json +635 -0
  243. schemas_export/crca_core/EstimateResult.schema.json +113 -0
  244. schemas_export/crca_core/IdentificationResult.schema.json +145 -0
  245. schemas_export/crca_core/InterventionDesignResult.schema.json +111 -0
  246. schemas_export/crca_core/LockedSpec.schema.json +646 -0
  247. schemas_export/crca_core/RefusalResult.schema.json +90 -0
  248. schemas_export/crca_core/ValidationReport.schema.json +62 -0
  249. scripts/build_lrm_dataset.py +80 -0
  250. scripts/export_crca_core_schemas.py +54 -0
  251. scripts/export_hf_lrm.py +37 -0
  252. scripts/export_ollama_gguf.py +45 -0
  253. scripts/generate_changelog.py +157 -0
  254. scripts/generate_crca_core_docs_from_schemas.py +86 -0
  255. scripts/run_crca_core_benchmarks.py +163 -0
  256. scripts/run_full_finetune.py +198 -0
  257. scripts/run_lrm_eval.py +31 -0
  258. templates/graph_management.py +29 -0
  259. tests/conftest.py +9 -0
  260. tests/test_core.py +2 -3
  261. tests/test_crca_core_discovery_tabular.py +15 -0
  262. tests/test_crca_core_estimate_dowhy.py +36 -0
  263. tests/test_crca_core_identify.py +18 -0
  264. tests/test_crca_core_intervention_design.py +36 -0
  265. tests/test_crca_core_linear_gaussian_scm.py +69 -0
  266. tests/test_crca_core_spec.py +25 -0
  267. tests/test_crca_core_timeseries_pcmci.py +15 -0
  268. tests/test_crca_llm_coauthor.py +12 -0
  269. tests/test_crca_llm_orchestrator.py +80 -0
  270. tests/test_hybrid_agent_llm_enhanced.py +556 -0
  271. tests/test_image_annotation_demo.py +376 -0
  272. tests/test_image_annotation_operational.py +408 -0
  273. tests/test_image_annotation_unit.py +551 -0
  274. tests/test_training_moe.py +13 -0
  275. training/__init__.py +42 -0
  276. training/datasets.py +140 -0
  277. training/deepspeed_zero2_0_5b.json +22 -0
  278. training/deepspeed_zero2_1_5b.json +22 -0
  279. training/deepspeed_zero3_0_5b.json +28 -0
  280. training/deepspeed_zero3_14b.json +28 -0
  281. training/deepspeed_zero3_h100_3gpu.json +20 -0
  282. training/deepspeed_zero3_offload.json +28 -0
  283. training/eval.py +92 -0
  284. training/finetune.py +516 -0
  285. training/public_datasets.py +89 -0
  286. training_data/react_train.jsonl +7473 -0
  287. utils/agent_discovery.py +311 -0
  288. utils/batch_processor.py +317 -0
  289. utils/conversation.py +78 -0
  290. utils/edit_distance.py +118 -0
  291. utils/formatter.py +33 -0
  292. utils/graph_reasoner.py +530 -0
  293. utils/rate_limiter.py +283 -0
  294. utils/router.py +2 -2
  295. utils/tool_discovery.py +307 -0
  296. webui/__init__.py +10 -0
  297. webui/app.py +229 -0
  298. webui/config.py +104 -0
  299. webui/static/css/style.css +332 -0
  300. webui/static/js/main.js +284 -0
  301. webui/templates/index.html +42 -0
  302. tests/test_crca_excel.py +0 -166
  303. tests/test_data_broker.py +0 -424
  304. tests/test_palantir.py +0 -349
  305. {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/WHEEL +0 -0
  306. {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/licenses/LICENSE +0 -0
webui/app.py ADDED
@@ -0,0 +1,229 @@
1
+ """
2
+ Flask application for CRCA Web UI.
3
+
4
+ Provides a simple REST API and serves the web interface.
5
+ """
6
+
7
+ import json
8
+ from typing import Dict, Any, Optional
9
+ from flask import Flask, request, jsonify, render_template, session
10
+ from loguru import logger
11
+
12
+ from webui.config import AGENTS, get_default_agent_key, get_agent_info, list_agents
13
+
14
+ # Initialize Flask app
15
+ app = Flask(__name__)
16
+ app.secret_key = "crca-webui-secret-key-change-in-production" # Change in production
17
+
18
+ # In-memory agent storage (session-based)
19
+ # In production, consider using Redis or database
20
+ _agent_instances: Dict[str, Any] = {}
21
+
22
+
23
+ def get_agent_instance(agent_key: str) -> Optional[Any]:
24
+ """
25
+ Get or create an agent instance.
26
+
27
+ Args:
28
+ agent_key: Agent registry key
29
+
30
+ Returns:
31
+ Agent instance or None if creation fails
32
+ """
33
+ # Check if we already have an instance for this session
34
+ session_id = session.get("session_id", "default")
35
+ cache_key = f"{session_id}_{agent_key}"
36
+
37
+ if cache_key in _agent_instances:
38
+ return _agent_instances[cache_key]
39
+
40
+ # Get agent info
41
+ agent_info = get_agent_info(agent_key)
42
+ if not agent_info:
43
+ logger.error(f"Agent '{agent_key}' not found in registry")
44
+ return None
45
+
46
+ # Create new instance
47
+ agent_class = agent_info["class"]
48
+ try:
49
+ if agent_key == "general":
50
+ # GeneralAgent can be initialized with no args (uses defaults)
51
+ instance = agent_class()
52
+ elif agent_key == "hybrid":
53
+ # HybridAgent can be initialized with no args (uses defaults)
54
+ instance = agent_class()
55
+ else:
56
+ # Generic initialization for other agents
57
+ instance = agent_class()
58
+
59
+ _agent_instances[cache_key] = instance
60
+ logger.info(f"Created {agent_info['name']} instance for session {session_id}")
61
+ return instance
62
+
63
+ except Exception as e:
64
+ logger.error(f"Failed to create agent instance: {e}")
65
+ return None
66
+
67
+
68
+ @app.route("/")
69
+ def index() -> str:
70
+ """Serve the main web UI page."""
71
+ return render_template("index.html")
72
+
73
+
74
+ @app.route("/api/agents", methods=["GET"])
75
+ def api_agents() -> Any:
76
+ """
77
+ Get list of available agents.
78
+
79
+ Returns:
80
+ JSON response with agent list
81
+ """
82
+ agents = list_agents()
83
+
84
+ # Format for frontend
85
+ agent_list = []
86
+ for key, info in agents.items():
87
+ agent_list.append({
88
+ "key": key,
89
+ "name": info["name"],
90
+ "description": info["description"],
91
+ "requires_llm": info.get("requires_llm", True),
92
+ "default": info.get("default", False),
93
+ })
94
+
95
+ return jsonify({
96
+ "agents": agent_list,
97
+ "default": get_default_agent_key(),
98
+ })
99
+
100
+
101
+ @app.route("/api/chat", methods=["POST"])
102
+ def api_chat() -> Any:
103
+ """
104
+ Handle chat message and return agent response.
105
+
106
+ Request body:
107
+ {
108
+ "message": str,
109
+ "agent_key": str (optional, uses default if not provided)
110
+ }
111
+
112
+ Returns:
113
+ JSON response with agent reply
114
+ """
115
+ # Initialize session if needed
116
+ if "session_id" not in session:
117
+ import uuid
118
+ session["session_id"] = str(uuid.uuid4())
119
+
120
+ try:
121
+ data = request.get_json()
122
+ if not data:
123
+ return jsonify({"error": "No JSON data provided"}), 400
124
+
125
+ message = data.get("message", "").strip()
126
+ if not message:
127
+ return jsonify({"error": "Message cannot be empty"}), 400
128
+
129
+ # Get agent key (use default if not provided)
130
+ agent_key = data.get("agent_key") or get_default_agent_key()
131
+ if not agent_key:
132
+ return jsonify({"error": "No agents available"}), 500
133
+
134
+ # Get agent instance
135
+ agent = get_agent_instance(agent_key)
136
+ if not agent:
137
+ return jsonify({"error": f"Failed to initialize agent '{agent_key}'"}), 500
138
+
139
+ # Get agent info for response
140
+ agent_info = get_agent_info(agent_key)
141
+ agent_name = agent_info["name"] if agent_info else agent_key
142
+
143
+ # Run agent
144
+ try:
145
+ response = agent.run(message)
146
+
147
+ # Ensure response is a string
148
+ if not isinstance(response, str):
149
+ response = str(response)
150
+
151
+ return jsonify({
152
+ "response": response,
153
+ "agent_type": agent_key,
154
+ "agent_name": agent_name,
155
+ })
156
+
157
+ except Exception as e:
158
+ logger.error(f"Error running agent: {e}")
159
+ return jsonify({
160
+ "error": f"Agent execution failed: {str(e)}",
161
+ "agent_type": agent_key,
162
+ }), 500
163
+
164
+ except Exception as e:
165
+ logger.error(f"Error in chat endpoint: {e}")
166
+ return jsonify({"error": f"Internal server error: {str(e)}"}), 500
167
+
168
+
169
+ @app.route("/api/switch", methods=["POST"])
170
+ def api_switch() -> Any:
171
+ """
172
+ Switch to a different agent.
173
+
174
+ Request body:
175
+ {
176
+ "agent_key": str
177
+ }
178
+
179
+ Returns:
180
+ JSON response confirming switch
181
+ """
182
+ try:
183
+ data = request.get_json()
184
+ if not data:
185
+ return jsonify({"error": "No JSON data provided"}), 400
186
+
187
+ agent_key = data.get("agent_key")
188
+ if not agent_key:
189
+ return jsonify({"error": "agent_key is required"}), 400
190
+
191
+ # Verify agent exists
192
+ agent_info = get_agent_info(agent_key)
193
+ if not agent_info:
194
+ return jsonify({"error": f"Agent '{agent_key}' not found"}), 404
195
+
196
+ # Clear cached instance for this session to force recreation
197
+ session_id = session.get("session_id", "default")
198
+ cache_key = f"{session_id}_{agent_key}"
199
+ if cache_key in _agent_instances:
200
+ del _agent_instances[cache_key]
201
+
202
+ return jsonify({
203
+ "success": True,
204
+ "agent_key": agent_key,
205
+ "agent_name": agent_info["name"],
206
+ })
207
+
208
+ except Exception as e:
209
+ logger.error(f"Error switching agent: {e}")
210
+ return jsonify({"error": f"Internal server error: {str(e)}"}), 500
211
+
212
+
213
+ @app.errorhandler(404)
214
+ def not_found(error: Any) -> Any:
215
+ """Handle 404 errors."""
216
+ return jsonify({"error": "Not found"}), 404
217
+
218
+
219
+ @app.errorhandler(500)
220
+ def internal_error(error: Any) -> Any:
221
+ """Handle 500 errors."""
222
+ return jsonify({"error": "Internal server error"}), 500
223
+
224
+
225
+ if __name__ == "__main__":
226
+ # Run development server
227
+ logger.info("Starting CRCA Web UI server...")
228
+ logger.info(f"Available agents: {list(AGENTS.keys())}")
229
+ app.run(host="0.0.0.0", port=5000, debug=True)
webui/config.py ADDED
@@ -0,0 +1,104 @@
1
+ """
2
+ Configuration registry for agents and tools.
3
+
4
+ This module provides an extensible registry system for adding new agents
5
+ and tools to the web UI without modifying core application code.
6
+ """
7
+
8
+ from typing import Dict, Any, Optional, Type
9
+ from loguru import logger
10
+
11
+ # Agent registry - add new agents here
12
+ AGENTS: Dict[str, Dict[str, Any]] = {}
13
+
14
+ # Tool registry - add new tools here
15
+ TOOLS: Dict[str, Dict[str, Any]] = {}
16
+
17
+ # Lazy imports to handle optional dependencies
18
+ try:
19
+ from branches.general_agent import GeneralAgent
20
+ GENERAL_AGENT_AVAILABLE = True
21
+ except ImportError as e:
22
+ GeneralAgent = None
23
+ GENERAL_AGENT_AVAILABLE = False
24
+ logger.warning(f"GeneralAgent not available: {e}")
25
+
26
+ try:
27
+ from architecture.hybrid.hybrid_agent import HybridAgent
28
+ HYBRID_AGENT_AVAILABLE = True
29
+ except ImportError as e:
30
+ HybridAgent = None
31
+ HYBRID_AGENT_AVAILABLE = False
32
+ logger.warning(f"HybridAgent not available: {e}")
33
+
34
+
35
+ def _register_agents() -> None:
36
+ """Register available agents in the AGENTS dictionary."""
37
+ global AGENTS
38
+
39
+ # Register GeneralAgent if available
40
+ if GENERAL_AGENT_AVAILABLE and GeneralAgent is not None:
41
+ AGENTS["general"] = {
42
+ "name": "General Agent",
43
+ "class": GeneralAgent,
44
+ "description": "LLM-powered general-purpose agent with causal reasoning capabilities",
45
+ "requires_llm": True,
46
+ "default": True, # This is the default agent
47
+ }
48
+ logger.info("Registered GeneralAgent")
49
+
50
+ # Register HybridAgent if available
51
+ if HYBRID_AGENT_AVAILABLE and HybridAgent is not None:
52
+ AGENTS["hybrid"] = {
53
+ "name": "Hybrid Agent",
54
+ "class": HybridAgent,
55
+ "description": "Symbolic-statistical agent (no LLM required)",
56
+ "requires_llm": False,
57
+ "default": False,
58
+ }
59
+ logger.info("Registered HybridAgent")
60
+
61
+
62
+ def get_default_agent_key() -> Optional[str]:
63
+ """
64
+ Get the key of the default agent.
65
+
66
+ Returns:
67
+ Agent key string or None if no agents available
68
+ """
69
+ for key, agent_info in AGENTS.items():
70
+ if agent_info.get("default", False):
71
+ return key
72
+
73
+ # If no default marked, return first available agent
74
+ if AGENTS:
75
+ return list(AGENTS.keys())[0]
76
+
77
+ return None
78
+
79
+
80
+ def get_agent_info(key: str) -> Optional[Dict[str, Any]]:
81
+ """
82
+ Get agent information by key.
83
+
84
+ Args:
85
+ key: Agent registry key
86
+
87
+ Returns:
88
+ Agent info dictionary or None if not found
89
+ """
90
+ return AGENTS.get(key)
91
+
92
+
93
+ def list_agents() -> Dict[str, Dict[str, Any]]:
94
+ """
95
+ List all registered agents.
96
+
97
+ Returns:
98
+ Dictionary of agent keys to agent info
99
+ """
100
+ return AGENTS.copy()
101
+
102
+
103
+ # Initialize agent registry on module import
104
+ _register_agents()
@@ -0,0 +1,332 @@
1
+ /* CRCA Web UI - European Professional Style */
2
+ /* Muted greys, whites, subtle blues - no bright colors, no rounded corners */
3
+
4
+ * {
5
+ margin: 0;
6
+ padding: 0;
7
+ box-sizing: border-box;
8
+ }
9
+
10
+ body {
11
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
12
+ background-color: #f8f9fa;
13
+ color: #2c2c2c;
14
+ line-height: 1.6;
15
+ height: 100vh;
16
+ display: flex;
17
+ flex-direction: column;
18
+ font-size: 14px;
19
+ }
20
+
21
+ /* Header */
22
+ .header {
23
+ background-color: #4a5568;
24
+ color: #ffffff;
25
+ padding: 1.25rem 2rem;
26
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
27
+ border-bottom: 2px solid #2d3748;
28
+ }
29
+
30
+ .header h1 {
31
+ font-size: 1.5rem;
32
+ font-weight: 600;
33
+ letter-spacing: 0.5px;
34
+ }
35
+
36
+ .header p {
37
+ font-size: 0.875rem;
38
+ opacity: 0.9;
39
+ margin-top: 0.25rem;
40
+ font-weight: 300;
41
+ }
42
+
43
+ /* Controls Bar */
44
+ .controls {
45
+ background-color: #ffffff;
46
+ padding: 1rem 2rem;
47
+ border-bottom: 1px solid #e2e8f0;
48
+ display: flex;
49
+ align-items: center;
50
+ gap: 1.5rem;
51
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
52
+ }
53
+
54
+ .agent-selector {
55
+ display: flex;
56
+ align-items: center;
57
+ gap: 0.75rem;
58
+ }
59
+
60
+ .agent-selector label {
61
+ font-weight: 500;
62
+ font-size: 0.875rem;
63
+ color: #4a5568;
64
+ text-transform: uppercase;
65
+ letter-spacing: 0.5px;
66
+ }
67
+
68
+ .agent-selector select {
69
+ padding: 0.5rem 1rem;
70
+ border: 1px solid #cbd5e0;
71
+ background-color: #ffffff;
72
+ font-size: 0.875rem;
73
+ cursor: pointer;
74
+ color: #2d3748;
75
+ font-family: inherit;
76
+ min-width: 200px;
77
+ transition: border-color 0.2s ease;
78
+ }
79
+
80
+ .agent-selector select:hover {
81
+ border-color: #718096;
82
+ }
83
+
84
+ .agent-selector select:focus {
85
+ outline: none;
86
+ border-color: #4a5568;
87
+ box-shadow: 0 0 0 2px rgba(74, 85, 104, 0.1);
88
+ }
89
+
90
+ .agent-info {
91
+ font-size: 0.8125rem;
92
+ color: #718096;
93
+ font-style: normal;
94
+ padding-left: 1rem;
95
+ border-left: 1px solid #e2e8f0;
96
+ }
97
+
98
+ /* Chat Container */
99
+ .chat-container {
100
+ flex: 1;
101
+ display: flex;
102
+ flex-direction: column;
103
+ overflow: hidden;
104
+ background-color: #ffffff;
105
+ margin: 1rem;
106
+ border: 1px solid #e2e8f0;
107
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
108
+ }
109
+
110
+ .chat-messages {
111
+ flex: 1;
112
+ overflow-y: auto;
113
+ padding: 1.5rem;
114
+ display: flex;
115
+ flex-direction: column;
116
+ gap: 1rem;
117
+ background-color: #fafbfc;
118
+ }
119
+
120
+ .chat-messages::-webkit-scrollbar {
121
+ width: 8px;
122
+ }
123
+
124
+ .chat-messages::-webkit-scrollbar-track {
125
+ background: #f1f5f9;
126
+ }
127
+
128
+ .chat-messages::-webkit-scrollbar-thumb {
129
+ background: #cbd5e0;
130
+ }
131
+
132
+ .chat-messages::-webkit-scrollbar-thumb:hover {
133
+ background: #a0aec0;
134
+ }
135
+
136
+ /* Messages */
137
+ .message {
138
+ max-width: 75%;
139
+ padding: 0.875rem 1.125rem;
140
+ word-wrap: break-word;
141
+ border: 1px solid transparent;
142
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
143
+ }
144
+
145
+ .message.user {
146
+ align-self: flex-end;
147
+ background-color: #4a5568;
148
+ color: #ffffff;
149
+ border-color: #2d3748;
150
+ }
151
+
152
+ .message.agent {
153
+ align-self: flex-start;
154
+ background-color: #ffffff;
155
+ color: #2d3748;
156
+ border-color: #e2e8f0;
157
+ }
158
+
159
+ .message.error {
160
+ align-self: flex-start;
161
+ background-color: #c53030;
162
+ color: #ffffff;
163
+ border-color: #9b2c2c;
164
+ }
165
+
166
+ .message-header {
167
+ font-size: 0.75rem;
168
+ opacity: 0.85;
169
+ margin-bottom: 0.375rem;
170
+ font-weight: 500;
171
+ text-transform: uppercase;
172
+ letter-spacing: 0.5px;
173
+ }
174
+
175
+ .message.user .message-header {
176
+ color: #e2e8f0;
177
+ }
178
+
179
+ .message.agent .message-header {
180
+ color: #718096;
181
+ }
182
+
183
+ .message-content {
184
+ white-space: pre-wrap;
185
+ line-height: 1.5;
186
+ font-size: 0.9375rem;
187
+ }
188
+
189
+ .message.user .message-content {
190
+ color: #ffffff;
191
+ }
192
+
193
+ .message.agent .message-content {
194
+ color: #2d3748;
195
+ }
196
+
197
+ /* Input Container */
198
+ .chat-input-container {
199
+ padding: 1.125rem 1.5rem;
200
+ border-top: 1px solid #e2e8f0;
201
+ display: flex;
202
+ gap: 0.75rem;
203
+ background-color: #ffffff;
204
+ align-items: flex-end;
205
+ }
206
+
207
+ .chat-input {
208
+ flex: 1;
209
+ padding: 0.75rem 1rem;
210
+ border: 1px solid #cbd5e0;
211
+ background-color: #ffffff;
212
+ font-size: 0.9375rem;
213
+ font-family: inherit;
214
+ resize: none;
215
+ min-height: 50px;
216
+ max-height: 150px;
217
+ color: #2d3748;
218
+ line-height: 1.5;
219
+ transition: border-color 0.2s ease;
220
+ }
221
+
222
+ .chat-input:focus {
223
+ outline: none;
224
+ border-color: #4a5568;
225
+ box-shadow: 0 0 0 2px rgba(74, 85, 104, 0.1);
226
+ }
227
+
228
+ .chat-input:disabled {
229
+ background-color: #f7fafc;
230
+ color: #a0aec0;
231
+ cursor: not-allowed;
232
+ }
233
+
234
+ .chat-input::placeholder {
235
+ color: #a0aec0;
236
+ }
237
+
238
+ .send-button {
239
+ padding: 0.75rem 1.75rem;
240
+ background-color: #4a5568;
241
+ color: #ffffff;
242
+ border: 1px solid #2d3748;
243
+ font-size: 0.9375rem;
244
+ cursor: pointer;
245
+ font-weight: 500;
246
+ transition: background-color 0.2s ease, border-color 0.2s ease;
247
+ text-transform: uppercase;
248
+ letter-spacing: 0.5px;
249
+ font-size: 0.8125rem;
250
+ min-width: 100px;
251
+ height: 50px;
252
+ }
253
+
254
+ .send-button:hover:not(:disabled) {
255
+ background-color: #2d3748;
256
+ border-color: #1a202c;
257
+ }
258
+
259
+ .send-button:active:not(:disabled) {
260
+ background-color: #1a202c;
261
+ }
262
+
263
+ .send-button:disabled {
264
+ background-color: #cbd5e0;
265
+ border-color: #a0aec0;
266
+ color: #718096;
267
+ cursor: not-allowed;
268
+ }
269
+
270
+ .send-button:focus {
271
+ outline: none;
272
+ box-shadow: 0 0 0 2px rgba(74, 85, 104, 0.2);
273
+ }
274
+
275
+ /* Loading Indicator */
276
+ .loading {
277
+ display: inline-block;
278
+ width: 12px;
279
+ height: 12px;
280
+ border: 2px solid rgba(255, 255, 255, 0.3);
281
+ border-top: 2px solid #ffffff;
282
+ animation: spin 0.8s linear infinite;
283
+ margin-right: 0.5rem;
284
+ vertical-align: middle;
285
+ }
286
+
287
+ @keyframes spin {
288
+ 0% {
289
+ transform: rotate(0deg);
290
+ }
291
+ 100% {
292
+ transform: rotate(360deg);
293
+ }
294
+ }
295
+
296
+ /* Empty State */
297
+ .empty-state {
298
+ text-align: center;
299
+ color: #a0aec0;
300
+ padding: 3rem;
301
+ font-style: italic;
302
+ font-size: 0.9375rem;
303
+ }
304
+
305
+ /* Typography Enhancements */
306
+ h1, h2, h3, h4, h5, h6 {
307
+ font-weight: 600;
308
+ color: #2d3748;
309
+ }
310
+
311
+ /* Focus States */
312
+ *:focus {
313
+ outline: none;
314
+ }
315
+
316
+ select:focus,
317
+ input:focus,
318
+ textarea:focus,
319
+ button:focus {
320
+ outline: none;
321
+ }
322
+
323
+ /* Selection */
324
+ ::selection {
325
+ background-color: #4a5568;
326
+ color: #ffffff;
327
+ }
328
+
329
+ ::-moz-selection {
330
+ background-color: #4a5568;
331
+ color: #ffffff;
332
+ }