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.
- CRCA.py +172 -7
- MODEL_CARD.md +53 -0
- PKG-INFO +8 -2
- RELEASE_NOTES.md +17 -0
- STABILITY.md +19 -0
- architecture/hybrid/consistency_engine.py +362 -0
- architecture/hybrid/conversation_manager.py +421 -0
- architecture/hybrid/explanation_generator.py +452 -0
- architecture/hybrid/few_shot_learner.py +533 -0
- architecture/hybrid/graph_compressor.py +286 -0
- architecture/hybrid/hybrid_agent.py +4398 -0
- architecture/hybrid/language_compiler.py +623 -0
- architecture/hybrid/main,py +0 -0
- architecture/hybrid/reasoning_tracker.py +322 -0
- architecture/hybrid/self_verifier.py +524 -0
- architecture/hybrid/task_decomposer.py +567 -0
- architecture/hybrid/text_corrector.py +341 -0
- benchmark_results/crca_core_benchmarks.json +178 -0
- branches/crca_sd/crca_sd_realtime.py +6 -2
- branches/general_agent/__init__.py +102 -0
- branches/general_agent/general_agent.py +1400 -0
- branches/general_agent/personality.py +169 -0
- branches/general_agent/utils/__init__.py +19 -0
- branches/general_agent/utils/prompt_builder.py +170 -0
- {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/METADATA +8 -2
- {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/RECORD +303 -20
- crca_core/__init__.py +35 -0
- crca_core/benchmarks/__init__.py +14 -0
- crca_core/benchmarks/synthetic_scm.py +103 -0
- crca_core/core/__init__.py +23 -0
- crca_core/core/api.py +120 -0
- crca_core/core/estimate.py +208 -0
- crca_core/core/godclass.py +72 -0
- crca_core/core/intervention_design.py +174 -0
- crca_core/core/lifecycle.py +48 -0
- crca_core/discovery/__init__.py +9 -0
- crca_core/discovery/tabular.py +193 -0
- crca_core/identify/__init__.py +171 -0
- crca_core/identify/backdoor.py +39 -0
- crca_core/identify/frontdoor.py +48 -0
- crca_core/identify/graph.py +106 -0
- crca_core/identify/id_algorithm.py +43 -0
- crca_core/identify/iv.py +48 -0
- crca_core/models/__init__.py +67 -0
- crca_core/models/provenance.py +56 -0
- crca_core/models/refusal.py +39 -0
- crca_core/models/result.py +83 -0
- crca_core/models/spec.py +151 -0
- crca_core/models/validation.py +68 -0
- crca_core/scm/__init__.py +9 -0
- crca_core/scm/linear_gaussian.py +198 -0
- crca_core/timeseries/__init__.py +6 -0
- crca_core/timeseries/pcmci.py +181 -0
- crca_llm/__init__.py +12 -0
- crca_llm/client.py +85 -0
- crca_llm/coauthor.py +118 -0
- crca_llm/orchestrator.py +289 -0
- crca_llm/types.py +21 -0
- crca_reasoning/__init__.py +16 -0
- crca_reasoning/critique.py +54 -0
- crca_reasoning/godclass.py +206 -0
- crca_reasoning/memory.py +24 -0
- crca_reasoning/rationale.py +10 -0
- crca_reasoning/react_controller.py +81 -0
- crca_reasoning/tool_router.py +97 -0
- crca_reasoning/types.py +40 -0
- crca_sd/__init__.py +15 -0
- crca_sd/crca_sd_core.py +2 -0
- crca_sd/crca_sd_governance.py +2 -0
- crca_sd/crca_sd_mpc.py +2 -0
- crca_sd/crca_sd_realtime.py +2 -0
- crca_sd/crca_sd_tui.py +2 -0
- cuda-keyring_1.1-1_all.deb +0 -0
- cuda-keyring_1.1-1_all.deb.1 +0 -0
- docs/IMAGE_ANNOTATION_USAGE.md +539 -0
- docs/INSTALL_DEEPSPEED.md +125 -0
- docs/api/branches/crca-cg.md +19 -0
- docs/api/branches/crca-q.md +27 -0
- docs/api/branches/crca-sd.md +37 -0
- docs/api/branches/general-agent.md +24 -0
- docs/api/branches/overview.md +19 -0
- docs/api/crca/agent-methods.md +62 -0
- docs/api/crca/operations.md +79 -0
- docs/api/crca/overview.md +32 -0
- docs/api/image-annotation/engine.md +52 -0
- docs/api/image-annotation/overview.md +17 -0
- docs/api/schemas/annotation.md +34 -0
- docs/api/schemas/core-schemas.md +82 -0
- docs/api/schemas/overview.md +32 -0
- docs/api/schemas/policy.md +30 -0
- docs/api/utils/conversation.md +22 -0
- docs/api/utils/graph-reasoner.md +32 -0
- docs/api/utils/overview.md +21 -0
- docs/api/utils/router.md +19 -0
- docs/api/utils/utilities.md +97 -0
- docs/architecture/causal-graphs.md +41 -0
- docs/architecture/data-flow.md +29 -0
- docs/architecture/design-principles.md +33 -0
- docs/architecture/hybrid-agent/components.md +38 -0
- docs/architecture/hybrid-agent/consistency.md +26 -0
- docs/architecture/hybrid-agent/overview.md +44 -0
- docs/architecture/hybrid-agent/reasoning.md +22 -0
- docs/architecture/llm-integration.md +26 -0
- docs/architecture/modular-structure.md +37 -0
- docs/architecture/overview.md +69 -0
- docs/architecture/policy-engine-arch.md +29 -0
- docs/branches/crca-cg/corposwarm.md +39 -0
- docs/branches/crca-cg/esg-scoring.md +30 -0
- docs/branches/crca-cg/multi-agent.md +35 -0
- docs/branches/crca-cg/overview.md +40 -0
- docs/branches/crca-q/alternative-data.md +55 -0
- docs/branches/crca-q/architecture.md +71 -0
- docs/branches/crca-q/backtesting.md +45 -0
- docs/branches/crca-q/causal-engine.md +33 -0
- docs/branches/crca-q/execution.md +39 -0
- docs/branches/crca-q/market-data.md +60 -0
- docs/branches/crca-q/overview.md +58 -0
- docs/branches/crca-q/philosophy.md +60 -0
- docs/branches/crca-q/portfolio-optimization.md +66 -0
- docs/branches/crca-q/risk-management.md +102 -0
- docs/branches/crca-q/setup.md +65 -0
- docs/branches/crca-q/signal-generation.md +61 -0
- docs/branches/crca-q/signal-validation.md +43 -0
- docs/branches/crca-sd/core.md +84 -0
- docs/branches/crca-sd/governance.md +53 -0
- docs/branches/crca-sd/mpc-solver.md +65 -0
- docs/branches/crca-sd/overview.md +59 -0
- docs/branches/crca-sd/realtime.md +28 -0
- docs/branches/crca-sd/tui.md +20 -0
- docs/branches/general-agent/overview.md +37 -0
- docs/branches/general-agent/personality.md +36 -0
- docs/branches/general-agent/prompt-builder.md +30 -0
- docs/changelog/index.md +79 -0
- docs/contributing/code-style.md +69 -0
- docs/contributing/documentation.md +43 -0
- docs/contributing/overview.md +29 -0
- docs/contributing/testing.md +29 -0
- docs/core/crcagent/async-operations.md +65 -0
- docs/core/crcagent/automatic-extraction.md +107 -0
- docs/core/crcagent/batch-prediction.md +80 -0
- docs/core/crcagent/bayesian-inference.md +60 -0
- docs/core/crcagent/causal-graph.md +92 -0
- docs/core/crcagent/counterfactuals.md +96 -0
- docs/core/crcagent/deterministic-simulation.md +78 -0
- docs/core/crcagent/dual-mode-operation.md +82 -0
- docs/core/crcagent/initialization.md +88 -0
- docs/core/crcagent/optimization.md +65 -0
- docs/core/crcagent/overview.md +63 -0
- docs/core/crcagent/time-series.md +57 -0
- docs/core/schemas/annotation.md +30 -0
- docs/core/schemas/core-schemas.md +82 -0
- docs/core/schemas/overview.md +30 -0
- docs/core/schemas/policy.md +41 -0
- docs/core/templates/base-agent.md +31 -0
- docs/core/templates/feature-mixins.md +31 -0
- docs/core/templates/overview.md +29 -0
- docs/core/templates/templates-guide.md +75 -0
- docs/core/tools/mcp-client.md +34 -0
- docs/core/tools/overview.md +24 -0
- docs/core/utils/conversation.md +27 -0
- docs/core/utils/graph-reasoner.md +29 -0
- docs/core/utils/overview.md +27 -0
- docs/core/utils/router.md +27 -0
- docs/core/utils/utilities.md +97 -0
- docs/css/custom.css +84 -0
- docs/examples/basic-usage.md +57 -0
- docs/examples/general-agent/general-agent-examples.md +50 -0
- docs/examples/hybrid-agent/hybrid-agent-examples.md +56 -0
- docs/examples/image-annotation/image-annotation-examples.md +54 -0
- docs/examples/integration/integration-examples.md +58 -0
- docs/examples/overview.md +37 -0
- docs/examples/trading/trading-examples.md +46 -0
- docs/features/causal-reasoning/advanced-topics.md +101 -0
- docs/features/causal-reasoning/counterfactuals.md +43 -0
- docs/features/causal-reasoning/do-calculus.md +50 -0
- docs/features/causal-reasoning/overview.md +47 -0
- docs/features/causal-reasoning/structural-models.md +52 -0
- docs/features/hybrid-agent/advanced-components.md +55 -0
- docs/features/hybrid-agent/core-components.md +64 -0
- docs/features/hybrid-agent/overview.md +34 -0
- docs/features/image-annotation/engine.md +82 -0
- docs/features/image-annotation/features.md +113 -0
- docs/features/image-annotation/integration.md +75 -0
- docs/features/image-annotation/overview.md +53 -0
- docs/features/image-annotation/quickstart.md +73 -0
- docs/features/policy-engine/doctrine-ledger.md +105 -0
- docs/features/policy-engine/monitoring.md +44 -0
- docs/features/policy-engine/mpc-control.md +89 -0
- docs/features/policy-engine/overview.md +46 -0
- docs/getting-started/configuration.md +225 -0
- docs/getting-started/first-agent.md +164 -0
- docs/getting-started/installation.md +144 -0
- docs/getting-started/quickstart.md +137 -0
- docs/index.md +118 -0
- docs/js/mathjax.js +13 -0
- docs/lrm/discovery_proof_notes.md +25 -0
- docs/lrm/finetune_full.md +83 -0
- docs/lrm/math_appendix.md +120 -0
- docs/lrm/overview.md +32 -0
- docs/mkdocs.yml +238 -0
- docs/stylesheets/extra.css +21 -0
- docs_generated/crca_core/CounterfactualResult.md +12 -0
- docs_generated/crca_core/DiscoveryHypothesisResult.md +13 -0
- docs_generated/crca_core/DraftSpec.md +13 -0
- docs_generated/crca_core/EstimateResult.md +13 -0
- docs_generated/crca_core/IdentificationResult.md +17 -0
- docs_generated/crca_core/InterventionDesignResult.md +12 -0
- docs_generated/crca_core/LockedSpec.md +15 -0
- docs_generated/crca_core/RefusalResult.md +12 -0
- docs_generated/crca_core/ValidationReport.md +9 -0
- docs_generated/crca_core/index.md +13 -0
- examples/general_agent_example.py +277 -0
- examples/general_agent_quickstart.py +202 -0
- examples/general_agent_simple.py +92 -0
- examples/hybrid_agent_auto_extraction.py +84 -0
- examples/hybrid_agent_dictionary_demo.py +104 -0
- examples/hybrid_agent_enhanced.py +179 -0
- examples/hybrid_agent_general_knowledge.py +107 -0
- examples/image_annotation_quickstart.py +328 -0
- examples/test_hybrid_fixes.py +77 -0
- image_annotation/__init__.py +27 -0
- image_annotation/annotation_engine.py +2593 -0
- install_cuda_wsl2.sh +59 -0
- install_deepspeed.sh +56 -0
- install_deepspeed_simple.sh +87 -0
- mkdocs.yml +252 -0
- ollama/Modelfile +8 -0
- prompts/__init__.py +2 -1
- prompts/default_crca.py +9 -1
- prompts/general_agent.py +227 -0
- prompts/image_annotation.py +56 -0
- pyproject.toml +17 -2
- requirements-docs.txt +10 -0
- requirements.txt +21 -2
- schemas/__init__.py +26 -1
- schemas/annotation.py +222 -0
- schemas/conversation.py +193 -0
- schemas/hybrid.py +211 -0
- schemas/reasoning.py +276 -0
- schemas_export/crca_core/CounterfactualResult.schema.json +108 -0
- schemas_export/crca_core/DiscoveryHypothesisResult.schema.json +113 -0
- schemas_export/crca_core/DraftSpec.schema.json +635 -0
- schemas_export/crca_core/EstimateResult.schema.json +113 -0
- schemas_export/crca_core/IdentificationResult.schema.json +145 -0
- schemas_export/crca_core/InterventionDesignResult.schema.json +111 -0
- schemas_export/crca_core/LockedSpec.schema.json +646 -0
- schemas_export/crca_core/RefusalResult.schema.json +90 -0
- schemas_export/crca_core/ValidationReport.schema.json +62 -0
- scripts/build_lrm_dataset.py +80 -0
- scripts/export_crca_core_schemas.py +54 -0
- scripts/export_hf_lrm.py +37 -0
- scripts/export_ollama_gguf.py +45 -0
- scripts/generate_changelog.py +157 -0
- scripts/generate_crca_core_docs_from_schemas.py +86 -0
- scripts/run_crca_core_benchmarks.py +163 -0
- scripts/run_full_finetune.py +198 -0
- scripts/run_lrm_eval.py +31 -0
- templates/graph_management.py +29 -0
- tests/conftest.py +9 -0
- tests/test_core.py +2 -3
- tests/test_crca_core_discovery_tabular.py +15 -0
- tests/test_crca_core_estimate_dowhy.py +36 -0
- tests/test_crca_core_identify.py +18 -0
- tests/test_crca_core_intervention_design.py +36 -0
- tests/test_crca_core_linear_gaussian_scm.py +69 -0
- tests/test_crca_core_spec.py +25 -0
- tests/test_crca_core_timeseries_pcmci.py +15 -0
- tests/test_crca_llm_coauthor.py +12 -0
- tests/test_crca_llm_orchestrator.py +80 -0
- tests/test_hybrid_agent_llm_enhanced.py +556 -0
- tests/test_image_annotation_demo.py +376 -0
- tests/test_image_annotation_operational.py +408 -0
- tests/test_image_annotation_unit.py +551 -0
- tests/test_training_moe.py +13 -0
- training/__init__.py +42 -0
- training/datasets.py +140 -0
- training/deepspeed_zero2_0_5b.json +22 -0
- training/deepspeed_zero2_1_5b.json +22 -0
- training/deepspeed_zero3_0_5b.json +28 -0
- training/deepspeed_zero3_14b.json +28 -0
- training/deepspeed_zero3_h100_3gpu.json +20 -0
- training/deepspeed_zero3_offload.json +28 -0
- training/eval.py +92 -0
- training/finetune.py +516 -0
- training/public_datasets.py +89 -0
- training_data/react_train.jsonl +7473 -0
- utils/agent_discovery.py +311 -0
- utils/batch_processor.py +317 -0
- utils/conversation.py +78 -0
- utils/edit_distance.py +118 -0
- utils/formatter.py +33 -0
- utils/graph_reasoner.py +530 -0
- utils/rate_limiter.py +283 -0
- utils/router.py +2 -2
- utils/tool_discovery.py +307 -0
- webui/__init__.py +10 -0
- webui/app.py +229 -0
- webui/config.py +104 -0
- webui/static/css/style.css +332 -0
- webui/static/js/main.js +284 -0
- webui/templates/index.html +42 -0
- tests/test_crca_excel.py +0 -166
- tests/test_data_broker.py +0 -424
- tests/test_palantir.py +0 -349
- {crca-1.4.0.dist-info → crca-1.5.0.dist-info}/WHEEL +0 -0
- {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
|
+
)
|
crca_reasoning/memory.py
ADDED
|
@@ -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,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
|
+
)
|
crca_reasoning/types.py
ADDED
|
@@ -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
|
+
|
crca_sd/crca_sd_core.py
ADDED
crca_sd/crca_sd_mpc.py
ADDED
crca_sd/crca_sd_tui.py
ADDED
|
Binary file
|
|
Binary file
|