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
crca_llm/types.py ADDED
@@ -0,0 +1,21 @@
1
+ """Typed outputs for crca_llm orchestrator."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, List, Optional
6
+
7
+ from pydantic import BaseModel, Field
8
+
9
+ from crca_core.models.refusal import RefusalResult
10
+ from crca_core.models.result import AnyResult
11
+ from crca_llm.coauthor import DraftBundle
12
+
13
+
14
+ class LLMRunResult(BaseModel):
15
+ """Container for LLM drafts + core results + refusals."""
16
+
17
+ draft_bundle: DraftBundle
18
+ core_results: List[AnyResult] = Field(default_factory=list)
19
+ refusals: List[RefusalResult] = Field(default_factory=list)
20
+ llm_metadata: Optional[dict] = None
21
+
@@ -0,0 +1,16 @@
1
+ """crca_reasoning: ReAct-style reasoning kernel with strict tool gating."""
2
+
3
+ from crca_reasoning.godclass import ReActGodClass
4
+ from crca_reasoning.react_controller import ReActController
5
+ from crca_reasoning.types import LRMPlanResult, ReActAction
6
+ from crca_reasoning.tool_router import ToolRouter
7
+ from crca_reasoning.memory import StructuredMemory
8
+
9
+ __all__ = [
10
+ "ReActGodClass",
11
+ "ReActController",
12
+ "LRMPlanResult",
13
+ "ReActAction",
14
+ "ToolRouter",
15
+ "StructuredMemory",
16
+ ]
@@ -0,0 +1,54 @@
1
+ """End-of-cycle critique schema and rules."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import List, Optional
6
+
7
+ from pydantic import BaseModel, Field
8
+
9
+ from crca_reasoning.types import ReActCycleTrace
10
+
11
+
12
+ class CritiqueIssue(BaseModel):
13
+ code: str
14
+ message: str
15
+ severity: str = "warning" # info|warning|error
16
+
17
+
18
+ class CritiqueResult(BaseModel):
19
+ issues: List[CritiqueIssue] = Field(default_factory=list)
20
+ score: float = 0.0
21
+ threshold: float = 1.0
22
+ should_revise: bool = False
23
+ notes: Optional[str] = None
24
+
25
+
26
+ def critique_cycle(trace: ReActCycleTrace) -> CritiqueResult:
27
+ issues: List[CritiqueIssue] = []
28
+ score = 0.0
29
+ threshold = 1.0
30
+ if trace.actions and not trace.observations:
31
+ issues.append(
32
+ CritiqueIssue(
33
+ code="NO_OBSERVATIONS",
34
+ message="Actions were proposed but no observations recorded.",
35
+ severity="error",
36
+ )
37
+ )
38
+ score += 1.0
39
+ if any(obs.refusal is not None for obs in trace.observations):
40
+ issues.append(
41
+ CritiqueIssue(
42
+ code="REFUSAL_OCCURRED",
43
+ message="At least one tool call resulted in refusal.",
44
+ severity="warning",
45
+ )
46
+ )
47
+ score += 0.5
48
+ should_revise = score >= threshold
49
+ return CritiqueResult(
50
+ issues=issues,
51
+ score=score,
52
+ threshold=threshold,
53
+ should_revise=should_revise,
54
+ )
@@ -0,0 +1,206 @@
1
+ """ReAct GodClass: controller + critique + memory + tool router in one."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Any, Callable, Dict, List, Optional
7
+
8
+ from crca_core.core.api import (
9
+ EstimatorConfig,
10
+ FeasibilityConstraints,
11
+ PCMCIConfig,
12
+ TabularDiscoveryConfig,
13
+ TargetQuery,
14
+ design_intervention,
15
+ discover_tabular,
16
+ discover_timeseries_pcmci,
17
+ identify_effect,
18
+ estimate_effect_dowhy,
19
+ simulate_counterfactual,
20
+ )
21
+ from crca_core.models.refusal import RefusalChecklistItem, RefusalReasonCode, RefusalResult
22
+ from crca_core.models.result import AnyResult, IdentificationResult
23
+ from crca_reasoning.types import (
24
+ LRMPlanResult,
25
+ RationaleTrace,
26
+ ReActAction,
27
+ ReActCycleTrace,
28
+ ReActObservation,
29
+ )
30
+
31
+
32
+ ReasonerFn = Callable[["ReActGodClass"], tuple[str, List[ReActAction], str]]
33
+
34
+
35
+ @dataclass
36
+ class ReActGodClass:
37
+ """All-in-one ReAct controller with strict gating and critique."""
38
+
39
+ max_cycles: int = 3
40
+ memory_store: List[Dict[str, Any]] = field(default_factory=list)
41
+ staged_store: List[Dict[str, Any]] = field(default_factory=list)
42
+ last_identification: Optional[IdentificationResult] = None
43
+
44
+ # -----------------
45
+ # Memory operations
46
+ # -----------------
47
+ def read_memory(self) -> List[Dict[str, Any]]:
48
+ return list(self.memory_store)
49
+
50
+ def stage_write(self, item: Dict[str, Any]) -> None:
51
+ self.staged_store.append(item)
52
+
53
+ def finalize_memory(self) -> None:
54
+ self.memory_store.extend(self.staged_store)
55
+ self.staged_store = []
56
+
57
+ # -----------------
58
+ # Critique mechanics
59
+ # -----------------
60
+ def critique_cycle(self, trace: ReActCycleTrace) -> Dict[str, Any]:
61
+ issues: List[Dict[str, Any]] = []
62
+ score = 0.0
63
+ threshold = 1.0
64
+ if trace.actions and not trace.observations:
65
+ issues.append(
66
+ {
67
+ "code": "NO_OBSERVATIONS",
68
+ "message": "Actions were proposed but no observations recorded.",
69
+ "severity": "error",
70
+ }
71
+ )
72
+ score += 1.0
73
+ if any(obs.refusal is not None for obs in trace.observations):
74
+ issues.append(
75
+ {
76
+ "code": "REFUSAL_OCCURRED",
77
+ "message": "At least one tool call resulted in refusal.",
78
+ "severity": "warning",
79
+ }
80
+ )
81
+ score += 0.5
82
+ return {
83
+ "issues": issues,
84
+ "score": score,
85
+ "threshold": threshold,
86
+ "should_revise": score >= threshold,
87
+ }
88
+
89
+ # -----------------
90
+ # Tool routing
91
+ # -----------------
92
+ def call_tool(self, *, tool_name: str, payload: Dict[str, Any]) -> AnyResult | RefusalResult:
93
+ if tool_name in {"identify", "estimate", "counterfactual", "design_intervention"}:
94
+ if payload.get("locked_spec") is None:
95
+ return RefusalResult(
96
+ message="LockedSpec required for this tool.",
97
+ reason_codes=[RefusalReasonCode.SPEC_NOT_LOCKED],
98
+ checklist=[
99
+ RefusalChecklistItem(item="Provide LockedSpec", rationale="Tool is gated.")
100
+ ],
101
+ suggested_next_steps=["Lock a spec and retry."],
102
+ )
103
+
104
+ if tool_name == "identify":
105
+ res = identify_effect(
106
+ locked_spec=payload["locked_spec"],
107
+ treatment=payload.get("treatment", ""),
108
+ outcome=payload.get("outcome", ""),
109
+ )
110
+ if isinstance(res, IdentificationResult):
111
+ self.last_identification = res
112
+ return res
113
+
114
+ if tool_name == "estimate":
115
+ ident = payload.get("identification_result") or self.last_identification
116
+ return estimate_effect_dowhy(
117
+ data=payload.get("data"),
118
+ locked_spec=payload["locked_spec"],
119
+ treatment=payload.get("treatment", ""),
120
+ outcome=payload.get("outcome", ""),
121
+ identification_result=ident,
122
+ config=payload.get("config", EstimatorConfig()),
123
+ )
124
+
125
+ if tool_name == "counterfactual":
126
+ return simulate_counterfactual(
127
+ locked_spec=payload["locked_spec"],
128
+ factual_observation=payload.get("factual_observation", {}),
129
+ intervention=payload.get("intervention", {}),
130
+ allow_partial_observation=payload.get("allow_partial_observation", False),
131
+ )
132
+
133
+ if tool_name == "design_intervention":
134
+ return design_intervention(
135
+ locked_spec=payload["locked_spec"],
136
+ target_query=payload.get("target_query", TargetQuery()),
137
+ constraints=payload.get("constraints", FeasibilityConstraints()),
138
+ )
139
+
140
+ if tool_name == "discover_tabular":
141
+ return discover_tabular(
142
+ payload.get("data"),
143
+ payload.get("config", TabularDiscoveryConfig()),
144
+ payload.get("assumptions"),
145
+ )
146
+
147
+ if tool_name == "discover_timeseries":
148
+ return discover_timeseries_pcmci(
149
+ payload.get("data"),
150
+ payload.get("config", PCMCIConfig()),
151
+ payload.get("assumptions"),
152
+ )
153
+
154
+ return RefusalResult(
155
+ message=f"Unknown tool: {tool_name}",
156
+ reason_codes=[RefusalReasonCode.UNSUPPORTED_OPERATION],
157
+ checklist=[RefusalChecklistItem(item="Use a supported tool", rationale="Unknown tool name.")],
158
+ )
159
+
160
+ # -----------------
161
+ # ReAct execution
162
+ # -----------------
163
+ def run(self, reasoner: ReasonerFn) -> LRMPlanResult:
164
+ cycle_traces: List[ReActCycleTrace] = []
165
+ core_results: List[AnyResult] = []
166
+ refusals: List[RefusalResult] = []
167
+ rationale = RationaleTrace()
168
+
169
+ for _ in range(self.max_cycles):
170
+ reasoning, actions, rationale_step = reasoner(self)
171
+ cycle = ReActCycleTrace(reasoning=reasoning, actions=actions, observations=[])
172
+ if rationale_step:
173
+ rationale.steps.append(rationale_step)
174
+
175
+ for action in actions:
176
+ result = self.call_tool(tool_name=action.tool_name, payload=action.payload)
177
+ if isinstance(result, RefusalResult):
178
+ obs = ReActObservation(tool_name=action.tool_name, refusal=result)
179
+ refusals.append(result)
180
+ else:
181
+ obs = ReActObservation(tool_name=action.tool_name, result=result)
182
+ core_results.append(result)
183
+ cycle.observations.append(obs)
184
+
185
+ critique = self.critique_cycle(cycle)
186
+ cycle.critique = critique
187
+ cycle_traces.append(cycle)
188
+
189
+ if critique.get("should_revise"):
190
+ continue
191
+ break
192
+
193
+ for res in core_results:
194
+ try:
195
+ self.stage_write(res.model_dump())
196
+ except Exception:
197
+ continue
198
+ self.finalize_memory()
199
+
200
+ return LRMPlanResult(
201
+ cycle_traces=cycle_traces,
202
+ rationale_trace=rationale,
203
+ core_results=core_results,
204
+ refusals=refusals,
205
+ finalized=True,
206
+ )
@@ -0,0 +1,24 @@
1
+ """Structured memory store for reasoning artifacts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Dict, List, Optional
6
+
7
+
8
+ class StructuredMemory:
9
+ """Write-on-finalize memory store."""
10
+
11
+ def __init__(self) -> None:
12
+ self._store: List[Dict[str, Any]] = []
13
+ self._staged: List[Dict[str, Any]] = []
14
+
15
+ def read_all(self) -> List[Dict[str, Any]]:
16
+ return list(self._store)
17
+
18
+ def stage_write(self, item: Dict[str, Any]) -> None:
19
+ self._staged.append(item)
20
+
21
+ def finalize(self) -> None:
22
+ self._store.extend(self._staged)
23
+ self._staged = []
24
+
@@ -0,0 +1,10 @@
1
+ """Rationale trace output (non-scientific)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class RationaleTrace(BaseModel):
9
+ steps: list[str] = Field(default_factory=list)
10
+
@@ -0,0 +1,81 @@
1
+ """Multi-cycle ReAct controller with strict tool gating and end-of-cycle critique."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+ from typing import Callable, List, Optional
7
+
8
+ from crca_core.models.refusal import RefusalResult
9
+ from crca_core.models.result import AnyResult
10
+ from crca_reasoning.critique import critique_cycle
11
+ from crca_reasoning.memory import StructuredMemory
12
+ from crca_reasoning.types import (
13
+ LRMPlanResult,
14
+ RationaleTrace,
15
+ ReActAction,
16
+ ReActCycleTrace,
17
+ ReActObservation,
18
+ )
19
+ from crca_reasoning.tool_router import ToolRouter
20
+
21
+
22
+ ReasonerFn = Callable[[StructuredMemory], tuple[str, List[ReActAction], str]]
23
+
24
+
25
+ @dataclass
26
+ class ReActController:
27
+ max_cycles: int = 3
28
+ tool_router: ToolRouter = field(default_factory=ToolRouter)
29
+ memory: StructuredMemory = field(default_factory=StructuredMemory)
30
+
31
+ def run(self, reasoner: ReasonerFn) -> LRMPlanResult:
32
+ cycle_traces: List[ReActCycleTrace] = []
33
+ core_results: List[AnyResult] = []
34
+ refusals: List[RefusalResult] = []
35
+ rationale = RationaleTrace()
36
+
37
+ for _ in range(self.max_cycles):
38
+ reasoning, actions, rationale_step = reasoner(self.memory)
39
+ cycle = ReActCycleTrace(reasoning=reasoning, actions=actions, observations=[])
40
+ if rationale_step:
41
+ rationale.steps.append(rationale_step)
42
+
43
+ for action in actions:
44
+ result = self.tool_router.call_tool(
45
+ tool_name=action.tool_name, payload=action.payload
46
+ )
47
+ if isinstance(result, RefusalResult):
48
+ obs = ReActObservation(
49
+ tool_name=action.tool_name, refusal=result
50
+ )
51
+ refusals.append(result)
52
+ else:
53
+ obs = ReActObservation(
54
+ tool_name=action.tool_name, result=result
55
+ )
56
+ core_results.append(result)
57
+ cycle.observations.append(obs)
58
+
59
+ critique = critique_cycle(cycle)
60
+ cycle.critique = critique.model_dump()
61
+ cycle_traces.append(cycle)
62
+
63
+ if critique.should_revise:
64
+ continue
65
+ break
66
+
67
+ # Write-on-finalize memory policy
68
+ for res in core_results:
69
+ try:
70
+ self.memory.stage_write(res.model_dump())
71
+ except Exception:
72
+ continue
73
+ self.memory.finalize()
74
+
75
+ return LRMPlanResult(
76
+ cycle_traces=cycle_traces,
77
+ rationale_trace=rationale,
78
+ core_results=core_results,
79
+ refusals=refusals,
80
+ finalized=True,
81
+ )
@@ -0,0 +1,97 @@
1
+ """Unified tool router with strict gating."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Dict, Optional
6
+
7
+ from crca_core.core.api import (
8
+ EstimatorConfig,
9
+ FeasibilityConstraints,
10
+ PCMCIConfig,
11
+ TabularDiscoveryConfig,
12
+ TargetQuery,
13
+ design_intervention,
14
+ discover_tabular,
15
+ discover_timeseries_pcmci,
16
+ identify_effect,
17
+ estimate_effect_dowhy,
18
+ simulate_counterfactual,
19
+ )
20
+ from crca_core.models.refusal import RefusalChecklistItem, RefusalReasonCode, RefusalResult
21
+ from crca_core.models.result import AnyResult, IdentificationResult
22
+ from crca_core.models.spec import LockedSpec
23
+
24
+
25
+ class ToolRouter:
26
+ """Routes tool calls with pre-Act gating."""
27
+
28
+ def __init__(self) -> None:
29
+ self.last_identification: Optional[IdentificationResult] = None
30
+
31
+ def call_tool(self, *, tool_name: str, payload: Dict[str, Any]) -> AnyResult | RefusalResult:
32
+ if tool_name in {"identify", "estimate", "counterfactual", "design_intervention"}:
33
+ if payload.get("locked_spec") is None:
34
+ return RefusalResult(
35
+ message="LockedSpec required for this tool.",
36
+ reason_codes=[RefusalReasonCode.SPEC_NOT_LOCKED],
37
+ checklist=[
38
+ RefusalChecklistItem(item="Provide LockedSpec", rationale="Tool is gated.")
39
+ ],
40
+ suggested_next_steps=["Lock a spec and retry."],
41
+ )
42
+
43
+ if tool_name == "identify":
44
+ res = identify_effect(
45
+ locked_spec=payload["locked_spec"],
46
+ treatment=payload.get("treatment", ""),
47
+ outcome=payload.get("outcome", ""),
48
+ )
49
+ if isinstance(res, IdentificationResult):
50
+ self.last_identification = res
51
+ return res
52
+
53
+ if tool_name == "estimate":
54
+ ident = payload.get("identification_result") or self.last_identification
55
+ return estimate_effect_dowhy(
56
+ data=payload.get("data"),
57
+ locked_spec=payload["locked_spec"],
58
+ treatment=payload.get("treatment", ""),
59
+ outcome=payload.get("outcome", ""),
60
+ identification_result=ident,
61
+ config=payload.get("config", EstimatorConfig()),
62
+ )
63
+
64
+ if tool_name == "counterfactual":
65
+ return simulate_counterfactual(
66
+ locked_spec=payload["locked_spec"],
67
+ factual_observation=payload.get("factual_observation", {}),
68
+ intervention=payload.get("intervention", {}),
69
+ allow_partial_observation=payload.get("allow_partial_observation", False),
70
+ )
71
+
72
+ if tool_name == "design_intervention":
73
+ return design_intervention(
74
+ locked_spec=payload["locked_spec"],
75
+ target_query=payload.get("target_query", TargetQuery()),
76
+ constraints=payload.get("constraints", FeasibilityConstraints()),
77
+ )
78
+
79
+ if tool_name == "discover_tabular":
80
+ return discover_tabular(
81
+ payload.get("data"),
82
+ payload.get("config", TabularDiscoveryConfig()),
83
+ payload.get("assumptions"),
84
+ )
85
+
86
+ if tool_name == "discover_timeseries":
87
+ return discover_timeseries_pcmci(
88
+ payload.get("data"),
89
+ payload.get("config", PCMCIConfig()),
90
+ payload.get("assumptions"),
91
+ )
92
+
93
+ return RefusalResult(
94
+ message=f"Unknown tool: {tool_name}",
95
+ reason_codes=[RefusalReasonCode.UNSUPPORTED_OPERATION],
96
+ checklist=[RefusalChecklistItem(item="Use a supported tool", rationale="Unknown tool name.")],
97
+ )
@@ -0,0 +1,40 @@
1
+ """Types for ReAct reasoning and outputs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ from pydantic import BaseModel, Field
8
+
9
+ from crca_core.models.refusal import RefusalResult
10
+ from crca_core.models.result import AnyResult
11
+
12
+
13
+ class ReActAction(BaseModel):
14
+ tool_name: str
15
+ payload: Dict[str, Any] = Field(default_factory=dict)
16
+
17
+
18
+ class ReActObservation(BaseModel):
19
+ tool_name: str
20
+ result: Optional[AnyResult] = None
21
+ refusal: Optional[RefusalResult] = None
22
+
23
+
24
+ class ReActCycleTrace(BaseModel):
25
+ reasoning: str
26
+ actions: List[ReActAction] = Field(default_factory=list)
27
+ observations: List[ReActObservation] = Field(default_factory=list)
28
+ critique: Optional[Dict[str, Any]] = None
29
+
30
+
31
+ class RationaleTrace(BaseModel):
32
+ steps: List[str] = Field(default_factory=list)
33
+
34
+
35
+ class LRMPlanResult(BaseModel):
36
+ cycle_traces: List[ReActCycleTrace] = Field(default_factory=list)
37
+ rationale_trace: Optional[RationaleTrace] = None
38
+ core_results: List[AnyResult] = Field(default_factory=list)
39
+ refusals: List[RefusalResult] = Field(default_factory=list)
40
+ finalized: bool = False
crca_sd/__init__.py ADDED
@@ -0,0 +1,15 @@
1
+ """Compatibility shim for tests/examples.
2
+
3
+ The actual CRCA-SD implementation lives under `branches/crca_sd/` in this repo.
4
+ This package re-exports those modules under the import path `crca_sd.*`.
5
+ """
6
+
7
+ from crca_sd.crca_sd_core import * # noqa: F401,F403
8
+ from crca_sd.crca_sd_mpc import * # noqa: F401,F403
9
+ from crca_sd.crca_sd_governance import * # noqa: F401,F403
10
+ from crca_sd.crca_sd_realtime import * # noqa: F401,F403
11
+ # NOTE: Do NOT import `crca_sd_tui` at package import time.
12
+ # It depends on Unix-only modules (e.g., `termios`) and breaks test collection on Windows.
13
+
14
+ __all__ = [] # populated by wildcard imports above
15
+
@@ -0,0 +1,2 @@
1
+ from branches.crca_sd.crca_sd_core import * # noqa: F401,F403
2
+
@@ -0,0 +1,2 @@
1
+ from branches.crca_sd.crca_sd_governance import * # noqa: F401,F403
2
+
crca_sd/crca_sd_mpc.py ADDED
@@ -0,0 +1,2 @@
1
+ from branches.crca_sd.crca_sd_mpc import * # noqa: F401,F403
2
+
@@ -0,0 +1,2 @@
1
+ from branches.crca_sd.crca_sd_realtime import * # noqa: F401,F403
2
+
crca_sd/crca_sd_tui.py ADDED
@@ -0,0 +1,2 @@
1
+ from branches.crca_sd.crca_sd_tui import * # noqa: F401,F403
2
+
Binary file
Binary file