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
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Task Decomposition Engine with Hierarchical Planning and Dependency Resolution.
|
|
3
|
+
|
|
4
|
+
Implements HTN planning with dependency DAG resolution, parallel execution
|
|
5
|
+
with dataflow semantics, and fault tolerance.
|
|
6
|
+
|
|
7
|
+
Theoretical Basis:
|
|
8
|
+
- Hierarchical Task Networks (HTN) (Erol et al. 1994)
|
|
9
|
+
- STRIPS planning (Fikes & Nilsson 1971)
|
|
10
|
+
- Dependency Graphs (Tarjan 1972)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Dict, List, Optional, Tuple, Any, Set
|
|
14
|
+
from collections import defaultdict, deque
|
|
15
|
+
from enum import Enum
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
import logging
|
|
18
|
+
import re
|
|
19
|
+
import time
|
|
20
|
+
import uuid
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TaskComplexity(Enum):
|
|
26
|
+
"""Task complexity levels."""
|
|
27
|
+
SIMPLE = "simple"
|
|
28
|
+
MODERATE = "moderate"
|
|
29
|
+
COMPLEX = "complex"
|
|
30
|
+
VERY_COMPLEX = "very_complex"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TaskStatus(Enum):
|
|
34
|
+
"""Task execution status."""
|
|
35
|
+
PENDING = "pending"
|
|
36
|
+
READY = "ready"
|
|
37
|
+
RUNNING = "running"
|
|
38
|
+
COMPLETED = "completed"
|
|
39
|
+
FAILED = "failed"
|
|
40
|
+
SKIPPED = "skipped"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class SubTask:
|
|
45
|
+
"""
|
|
46
|
+
Represents a subtask in the decomposition.
|
|
47
|
+
|
|
48
|
+
Attributes:
|
|
49
|
+
task_id: Unique task identifier
|
|
50
|
+
description: Task description
|
|
51
|
+
inputs: Required inputs
|
|
52
|
+
outputs: Expected outputs
|
|
53
|
+
dependencies: List of task IDs this task depends on
|
|
54
|
+
complexity: Estimated complexity
|
|
55
|
+
status: Current execution status
|
|
56
|
+
result: Task result (if completed)
|
|
57
|
+
error: Error message (if failed)
|
|
58
|
+
"""
|
|
59
|
+
task_id: str
|
|
60
|
+
description: str
|
|
61
|
+
inputs: List[str] = field(default_factory=list)
|
|
62
|
+
outputs: List[str] = field(default_factory=list)
|
|
63
|
+
dependencies: List[str] = field(default_factory=list)
|
|
64
|
+
complexity: TaskComplexity = TaskComplexity.SIMPLE
|
|
65
|
+
status: TaskStatus = TaskStatus.PENDING
|
|
66
|
+
result: Optional[Any] = None
|
|
67
|
+
error: Optional[str] = None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class TaskAnalyzer:
|
|
71
|
+
"""
|
|
72
|
+
Implements task complexity analysis and decomposition.
|
|
73
|
+
|
|
74
|
+
Features:
|
|
75
|
+
- Complexity detection using Kolmogorov complexity estimation
|
|
76
|
+
- Sub-task generation using decomposition rules
|
|
77
|
+
- Dependency analysis building dependency DAG
|
|
78
|
+
- Plan generation with topological ordering
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def __init__(self):
|
|
82
|
+
"""Initialize task analyzer."""
|
|
83
|
+
self.decomposition_rules: List[Dict[str, Any]] = []
|
|
84
|
+
self.complexity_threshold = 50 # Threshold for decomposition
|
|
85
|
+
|
|
86
|
+
def analyze_task(
|
|
87
|
+
self,
|
|
88
|
+
task: str
|
|
89
|
+
) -> Tuple[TaskComplexity, bool]:
|
|
90
|
+
"""
|
|
91
|
+
Analyze task complexity.
|
|
92
|
+
|
|
93
|
+
Uses Kolmogorov complexity estimation: K(task) ≈ length of compressed representation.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
task: Task description
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Tuple of (complexity, should_decompose)
|
|
100
|
+
"""
|
|
101
|
+
# Simple complexity estimation: length and keyword analysis
|
|
102
|
+
task_length = len(task)
|
|
103
|
+
complexity_keywords = [
|
|
104
|
+
'analyze', 'compare', 'evaluate', 'synthesize', 'multiple',
|
|
105
|
+
'complex', 'several', 'various', 'different'
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
keyword_count = sum(1 for kw in complexity_keywords if kw in task.lower())
|
|
109
|
+
|
|
110
|
+
# Estimate complexity
|
|
111
|
+
if task_length < 50 and keyword_count == 0:
|
|
112
|
+
complexity = TaskComplexity.SIMPLE
|
|
113
|
+
should_decompose = False
|
|
114
|
+
elif task_length < 100 and keyword_count < 2:
|
|
115
|
+
complexity = TaskComplexity.MODERATE
|
|
116
|
+
should_decompose = False
|
|
117
|
+
elif task_length < 200 or keyword_count >= 2:
|
|
118
|
+
complexity = TaskComplexity.COMPLEX
|
|
119
|
+
should_decompose = True
|
|
120
|
+
else:
|
|
121
|
+
complexity = TaskComplexity.VERY_COMPLEX
|
|
122
|
+
should_decompose = True
|
|
123
|
+
|
|
124
|
+
return complexity, should_decompose
|
|
125
|
+
|
|
126
|
+
def decompose_task(
|
|
127
|
+
self,
|
|
128
|
+
task: str,
|
|
129
|
+
decomposition_rules: Optional[List[Dict[str, Any]]] = None
|
|
130
|
+
) -> List[SubTask]:
|
|
131
|
+
"""
|
|
132
|
+
Decompose task into subtasks.
|
|
133
|
+
|
|
134
|
+
Algorithm:
|
|
135
|
+
function decompose_task(task):
|
|
136
|
+
if is_primitive(task):
|
|
137
|
+
return [task]
|
|
138
|
+
decomposition_rules = get_applicable_rules(task)
|
|
139
|
+
best_rule = argmin(rule.complexity for rule in decomposition_rules)
|
|
140
|
+
subtasks = apply_decomposition(best_rule, task)
|
|
141
|
+
return [decompose_task(t) for t in subtasks].flatten()
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
task: Task to decompose
|
|
145
|
+
decomposition_rules: Optional decomposition rules
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
List of subtasks
|
|
149
|
+
"""
|
|
150
|
+
if decomposition_rules is None:
|
|
151
|
+
decomposition_rules = self._get_default_rules()
|
|
152
|
+
|
|
153
|
+
# Check if task is primitive (simple enough)
|
|
154
|
+
complexity, should_decompose = self.analyze_task(task)
|
|
155
|
+
if not should_decompose:
|
|
156
|
+
# Return as single primitive task
|
|
157
|
+
return [SubTask(
|
|
158
|
+
task_id=f"task_{int(time.time() * 1000)}",
|
|
159
|
+
description=task,
|
|
160
|
+
complexity=complexity
|
|
161
|
+
)]
|
|
162
|
+
|
|
163
|
+
# Apply decomposition rules
|
|
164
|
+
applicable_rules = self._get_applicable_rules(task, decomposition_rules)
|
|
165
|
+
if not applicable_rules:
|
|
166
|
+
# No applicable rules, return as single task
|
|
167
|
+
return [SubTask(
|
|
168
|
+
task_id=f"task_{int(time.time() * 1000)}",
|
|
169
|
+
description=task,
|
|
170
|
+
complexity=complexity
|
|
171
|
+
)]
|
|
172
|
+
|
|
173
|
+
# Select best rule (lowest complexity)
|
|
174
|
+
best_rule = min(applicable_rules, key=lambda r: r.get('complexity', 100))
|
|
175
|
+
|
|
176
|
+
# Apply decomposition
|
|
177
|
+
subtasks = self._apply_decomposition(task, best_rule)
|
|
178
|
+
|
|
179
|
+
# Recursively decompose subtasks
|
|
180
|
+
all_subtasks = []
|
|
181
|
+
for subtask_desc in subtasks:
|
|
182
|
+
sub_subtasks = self.decompose_task(subtask_desc, decomposition_rules)
|
|
183
|
+
all_subtasks.extend(sub_subtasks)
|
|
184
|
+
|
|
185
|
+
return all_subtasks
|
|
186
|
+
|
|
187
|
+
def _get_default_rules(self) -> List[Dict[str, Any]]:
|
|
188
|
+
"""Get default decomposition rules."""
|
|
189
|
+
return [
|
|
190
|
+
{
|
|
191
|
+
'pattern': r'analyze\s+(.+?)\s+and\s+(.+?)',
|
|
192
|
+
'decomposition': ['analyze {0}', 'analyze {1}'],
|
|
193
|
+
'complexity': 2
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
'pattern': r'compare\s+(.+?)\s+with\s+(.+?)',
|
|
197
|
+
'decomposition': ['analyze {0}', 'analyze {1}', 'compare results'],
|
|
198
|
+
'complexity': 3
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
'pattern': r'(.+?)\s+then\s+(.+?)',
|
|
202
|
+
'decomposition': ['{0}', '{1}'],
|
|
203
|
+
'complexity': 2
|
|
204
|
+
}
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
def _get_applicable_rules(
|
|
208
|
+
self,
|
|
209
|
+
task: str,
|
|
210
|
+
rules: List[Dict[str, Any]]
|
|
211
|
+
) -> List[Dict[str, Any]]:
|
|
212
|
+
"""Get applicable decomposition rules."""
|
|
213
|
+
applicable = []
|
|
214
|
+
for rule in rules:
|
|
215
|
+
pattern = rule.get('pattern', '')
|
|
216
|
+
if pattern and re.search(pattern, task, re.IGNORECASE):
|
|
217
|
+
applicable.append(rule)
|
|
218
|
+
return applicable
|
|
219
|
+
|
|
220
|
+
def _apply_decomposition(
|
|
221
|
+
self,
|
|
222
|
+
task: str,
|
|
223
|
+
rule: Dict[str, Any]
|
|
224
|
+
) -> List[str]:
|
|
225
|
+
"""Apply decomposition rule to task."""
|
|
226
|
+
pattern = rule.get('pattern', '')
|
|
227
|
+
decomposition = rule.get('decomposition', [])
|
|
228
|
+
|
|
229
|
+
match = re.search(pattern, task, re.IGNORECASE)
|
|
230
|
+
if not match:
|
|
231
|
+
return [task]
|
|
232
|
+
|
|
233
|
+
# Substitute matched groups
|
|
234
|
+
subtasks = []
|
|
235
|
+
for subtask_template in decomposition:
|
|
236
|
+
subtask = subtask_template
|
|
237
|
+
for i, group in enumerate(match.groups()):
|
|
238
|
+
subtask = subtask.replace(f'{{{i}}}', group)
|
|
239
|
+
subtasks.append(subtask)
|
|
240
|
+
|
|
241
|
+
return subtasks if subtasks else [task]
|
|
242
|
+
|
|
243
|
+
def build_dependency_graph(
|
|
244
|
+
self,
|
|
245
|
+
subtasks: List[SubTask]
|
|
246
|
+
) -> Dict[str, List[str]]:
|
|
247
|
+
"""
|
|
248
|
+
Build dependency DAG from subtasks.
|
|
249
|
+
|
|
250
|
+
D = (T, E_dep) where (Tᵢ, Tⱼ) ∈ E_dep means Tᵢ must precede Tⱼ.
|
|
251
|
+
|
|
252
|
+
O(n²) complexity for dependency analysis.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
subtasks: List of subtasks
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
Dictionary mapping task_id to list of dependent task IDs
|
|
259
|
+
"""
|
|
260
|
+
dependencies: Dict[str, List[str]] = defaultdict(list)
|
|
261
|
+
|
|
262
|
+
# Build task index
|
|
263
|
+
task_index = {task.task_id: task for task in subtasks}
|
|
264
|
+
|
|
265
|
+
# Analyze dependencies based on inputs/outputs
|
|
266
|
+
for task in subtasks:
|
|
267
|
+
for other_task in subtasks:
|
|
268
|
+
if task.task_id == other_task.task_id:
|
|
269
|
+
continue
|
|
270
|
+
|
|
271
|
+
# Check if other_task's outputs match task's inputs
|
|
272
|
+
if any(output in task.inputs for output in other_task.outputs):
|
|
273
|
+
dependencies[task.task_id].append(other_task.task_id)
|
|
274
|
+
|
|
275
|
+
return dict(dependencies)
|
|
276
|
+
|
|
277
|
+
def generate_execution_plan(
|
|
278
|
+
self,
|
|
279
|
+
subtasks: List[SubTask],
|
|
280
|
+
dependencies: Dict[str, List[str]]
|
|
281
|
+
) -> List[str]:
|
|
282
|
+
"""
|
|
283
|
+
Generate execution plan respecting topological ordering.
|
|
284
|
+
|
|
285
|
+
O(n log n) complexity for topological sort.
|
|
286
|
+
|
|
287
|
+
Args:
|
|
288
|
+
subtasks: List of subtasks
|
|
289
|
+
dependencies: Dependency graph
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
List of task IDs in execution order
|
|
293
|
+
"""
|
|
294
|
+
# Kahn's algorithm for topological sort
|
|
295
|
+
in_degree: Dict[str, int] = defaultdict(int)
|
|
296
|
+
task_ids = {task.task_id for task in subtasks}
|
|
297
|
+
|
|
298
|
+
# Initialize in-degrees
|
|
299
|
+
for task_id in task_ids:
|
|
300
|
+
in_degree[task_id] = 0
|
|
301
|
+
|
|
302
|
+
# Count in-degrees
|
|
303
|
+
for task_id, deps in dependencies.items():
|
|
304
|
+
for dep in deps:
|
|
305
|
+
in_degree[dep] += 1
|
|
306
|
+
|
|
307
|
+
# Find tasks with no dependencies
|
|
308
|
+
queue = deque([task_id for task_id in task_ids if in_degree[task_id] == 0])
|
|
309
|
+
execution_order = []
|
|
310
|
+
|
|
311
|
+
while queue:
|
|
312
|
+
task_id = queue.popleft()
|
|
313
|
+
execution_order.append(task_id)
|
|
314
|
+
|
|
315
|
+
# Reduce in-degree of dependent tasks
|
|
316
|
+
for dep in dependencies.get(task_id, []):
|
|
317
|
+
in_degree[dep] -= 1
|
|
318
|
+
if in_degree[dep] == 0:
|
|
319
|
+
queue.append(dep)
|
|
320
|
+
|
|
321
|
+
# Check for cycles (if not all tasks in execution order)
|
|
322
|
+
if len(execution_order) < len(task_ids):
|
|
323
|
+
logger.warning("Circular dependencies detected in task graph")
|
|
324
|
+
# Add remaining tasks (may have cycles)
|
|
325
|
+
remaining = task_ids - set(execution_order)
|
|
326
|
+
execution_order.extend(remaining)
|
|
327
|
+
|
|
328
|
+
return execution_order
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
class SubTaskExecutor:
|
|
332
|
+
"""
|
|
333
|
+
Implements parallel execution with dependency resolution and fault tolerance.
|
|
334
|
+
|
|
335
|
+
Features:
|
|
336
|
+
- Topological sort execution order
|
|
337
|
+
- Dataflow execution semantics
|
|
338
|
+
- Result aggregation
|
|
339
|
+
- Partial failure handling with rollback
|
|
340
|
+
"""
|
|
341
|
+
|
|
342
|
+
def __init__(self):
|
|
343
|
+
"""Initialize subtask executor."""
|
|
344
|
+
self.execution_results: Dict[str, Any] = {}
|
|
345
|
+
self.execution_history: List[Dict[str, Any]] = []
|
|
346
|
+
|
|
347
|
+
def execute_plan(
|
|
348
|
+
self,
|
|
349
|
+
subtasks: List[SubTask],
|
|
350
|
+
execution_order: List[str],
|
|
351
|
+
dependencies: Dict[str, List[str]],
|
|
352
|
+
executor_func: Optional[callable] = None
|
|
353
|
+
) -> Dict[str, Any]:
|
|
354
|
+
"""
|
|
355
|
+
Execute plan with dependency resolution.
|
|
356
|
+
|
|
357
|
+
Algorithm:
|
|
358
|
+
function execute_plan(plan, dependencies):
|
|
359
|
+
execution_order = topological_sort(plan, dependencies)
|
|
360
|
+
results = {}
|
|
361
|
+
for task in execution_order:
|
|
362
|
+
inputs = [results[dep] for dep in dependencies[task]]
|
|
363
|
+
results[task] = execute(task, inputs)
|
|
364
|
+
return aggregate(results)
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
subtasks: List of subtasks
|
|
368
|
+
execution_order: Execution order (topological sort)
|
|
369
|
+
dependencies: Dependency graph
|
|
370
|
+
executor_func: Optional function to execute tasks
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
Aggregated results
|
|
374
|
+
"""
|
|
375
|
+
task_index = {task.task_id: task for task in subtasks}
|
|
376
|
+
results = {}
|
|
377
|
+
failed_tasks = set()
|
|
378
|
+
|
|
379
|
+
for task_id in execution_order:
|
|
380
|
+
task = task_index.get(task_id)
|
|
381
|
+
if not task:
|
|
382
|
+
continue
|
|
383
|
+
|
|
384
|
+
# Check if dependencies are ready
|
|
385
|
+
deps = dependencies.get(task_id, [])
|
|
386
|
+
if any(dep in failed_tasks for dep in deps):
|
|
387
|
+
# Dependency failed, skip this task
|
|
388
|
+
task.status = TaskStatus.SKIPPED
|
|
389
|
+
task.error = "Dependency failed"
|
|
390
|
+
continue
|
|
391
|
+
|
|
392
|
+
# Get inputs from dependencies
|
|
393
|
+
inputs = [results.get(dep) for dep in deps]
|
|
394
|
+
|
|
395
|
+
# Execute task
|
|
396
|
+
try:
|
|
397
|
+
task.status = TaskStatus.RUNNING
|
|
398
|
+
if executor_func:
|
|
399
|
+
result = executor_func(task, inputs)
|
|
400
|
+
else:
|
|
401
|
+
result = self._default_execute(task, inputs)
|
|
402
|
+
|
|
403
|
+
task.result = result
|
|
404
|
+
task.status = TaskStatus.COMPLETED
|
|
405
|
+
results[task_id] = result
|
|
406
|
+
|
|
407
|
+
except Exception as e:
|
|
408
|
+
task.status = TaskStatus.FAILED
|
|
409
|
+
task.error = str(e)
|
|
410
|
+
failed_tasks.add(task_id)
|
|
411
|
+
|
|
412
|
+
# Rollback dependent tasks
|
|
413
|
+
self._rollback_dependents(task_id, dependencies, task_index)
|
|
414
|
+
|
|
415
|
+
# Aggregate results
|
|
416
|
+
return self._aggregate_results(results, subtasks)
|
|
417
|
+
|
|
418
|
+
def _default_execute(
|
|
419
|
+
self,
|
|
420
|
+
task: SubTask,
|
|
421
|
+
inputs: List[Any]
|
|
422
|
+
) -> Any:
|
|
423
|
+
"""
|
|
424
|
+
Default task execution (placeholder).
|
|
425
|
+
|
|
426
|
+
Args:
|
|
427
|
+
task: Task to execute
|
|
428
|
+
inputs: Input values from dependencies
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
Task result
|
|
432
|
+
"""
|
|
433
|
+
# Placeholder: return task description
|
|
434
|
+
return {
|
|
435
|
+
'task_id': task.task_id,
|
|
436
|
+
'description': task.description,
|
|
437
|
+
'inputs': inputs,
|
|
438
|
+
'status': 'completed'
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
def _rollback_dependents(
|
|
442
|
+
self,
|
|
443
|
+
failed_task_id: str,
|
|
444
|
+
dependencies: Dict[str, List[str]],
|
|
445
|
+
task_index: Dict[str, SubTask]
|
|
446
|
+
) -> None:
|
|
447
|
+
"""
|
|
448
|
+
Rollback tasks that depend on failed task.
|
|
449
|
+
|
|
450
|
+
Args:
|
|
451
|
+
failed_task_id: ID of failed task
|
|
452
|
+
dependencies: Dependency graph
|
|
453
|
+
task_index: Task index
|
|
454
|
+
"""
|
|
455
|
+
# Find tasks that depend on failed task
|
|
456
|
+
for task_id, deps in dependencies.items():
|
|
457
|
+
if failed_task_id in deps:
|
|
458
|
+
task = task_index.get(task_id)
|
|
459
|
+
if task and task.status == TaskStatus.RUNNING:
|
|
460
|
+
task.status = TaskStatus.FAILED
|
|
461
|
+
task.error = f"Dependency {failed_task_id} failed"
|
|
462
|
+
|
|
463
|
+
def _aggregate_results(
|
|
464
|
+
self,
|
|
465
|
+
results: Dict[str, Any],
|
|
466
|
+
subtasks: List[SubTask]
|
|
467
|
+
) -> Dict[str, Any]:
|
|
468
|
+
"""
|
|
469
|
+
Aggregate results from all subtasks.
|
|
470
|
+
|
|
471
|
+
Args:
|
|
472
|
+
results: Dictionary of task results
|
|
473
|
+
subtasks: List of subtasks
|
|
474
|
+
|
|
475
|
+
Returns:
|
|
476
|
+
Aggregated results
|
|
477
|
+
"""
|
|
478
|
+
return {
|
|
479
|
+
'results': results,
|
|
480
|
+
'completed_tasks': [t.task_id for t in subtasks if t.status == TaskStatus.COMPLETED],
|
|
481
|
+
'failed_tasks': [t.task_id for t in subtasks if t.status == TaskStatus.FAILED],
|
|
482
|
+
'skipped_tasks': [t.task_id for t in subtasks if t.status == TaskStatus.SKIPPED],
|
|
483
|
+
'total_tasks': len(subtasks)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
class PlanGenerator:
|
|
488
|
+
"""
|
|
489
|
+
Implements optimal planning with complexity estimation.
|
|
490
|
+
|
|
491
|
+
Features:
|
|
492
|
+
- Step-by-step plan generation
|
|
493
|
+
- Complexity estimation
|
|
494
|
+
- Information requirement identification
|
|
495
|
+
- Intermediate step suggestion
|
|
496
|
+
"""
|
|
497
|
+
|
|
498
|
+
def __init__(self, task_analyzer: TaskAnalyzer):
|
|
499
|
+
"""
|
|
500
|
+
Initialize plan generator.
|
|
501
|
+
|
|
502
|
+
Args:
|
|
503
|
+
task_analyzer: TaskAnalyzer instance
|
|
504
|
+
"""
|
|
505
|
+
self.task_analyzer = task_analyzer
|
|
506
|
+
|
|
507
|
+
def generate_plan(
|
|
508
|
+
self,
|
|
509
|
+
task: str
|
|
510
|
+
) -> Dict[str, Any]:
|
|
511
|
+
"""
|
|
512
|
+
Generate execution plan for task.
|
|
513
|
+
|
|
514
|
+
Args:
|
|
515
|
+
task: Task description
|
|
516
|
+
|
|
517
|
+
Returns:
|
|
518
|
+
Plan dictionary with subtasks, dependencies, execution order
|
|
519
|
+
"""
|
|
520
|
+
# Decompose task
|
|
521
|
+
subtasks = self.task_analyzer.decompose_task(task)
|
|
522
|
+
|
|
523
|
+
# Build dependency graph
|
|
524
|
+
dependencies = self.task_analyzer.build_dependency_graph(subtasks)
|
|
525
|
+
|
|
526
|
+
# Generate execution order
|
|
527
|
+
execution_order = self.task_analyzer.generate_execution_plan(subtasks, dependencies)
|
|
528
|
+
|
|
529
|
+
# Estimate complexity
|
|
530
|
+
total_complexity = sum(
|
|
531
|
+
self._estimate_complexity(t.description) for t in subtasks
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
# Identify information requirements
|
|
535
|
+
required_inputs = self._identify_required_inputs(subtasks, dependencies)
|
|
536
|
+
|
|
537
|
+
return {
|
|
538
|
+
'task': task,
|
|
539
|
+
'subtasks': subtasks,
|
|
540
|
+
'dependencies': dependencies,
|
|
541
|
+
'execution_order': execution_order,
|
|
542
|
+
'total_complexity': total_complexity,
|
|
543
|
+
'required_inputs': required_inputs,
|
|
544
|
+
'estimated_steps': len(subtasks)
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
def _estimate_complexity(self, task_description: str) -> int:
|
|
548
|
+
"""Estimate computational complexity of task."""
|
|
549
|
+
# Simple estimation based on length and keywords
|
|
550
|
+
length = len(task_description)
|
|
551
|
+
complexity_keywords = ['analyze', 'compare', 'evaluate', 'synthesize']
|
|
552
|
+
keyword_count = sum(1 for kw in complexity_keywords if kw in task_description.lower())
|
|
553
|
+
|
|
554
|
+
return length // 10 + keyword_count * 5
|
|
555
|
+
|
|
556
|
+
def _identify_required_inputs(
|
|
557
|
+
self,
|
|
558
|
+
subtasks: List[SubTask],
|
|
559
|
+
dependencies: Dict[str, List[str]]
|
|
560
|
+
) -> Set[str]:
|
|
561
|
+
"""Identify required inputs for all subtasks."""
|
|
562
|
+
required = set()
|
|
563
|
+
for task in subtasks:
|
|
564
|
+
# Tasks with no dependencies need external inputs
|
|
565
|
+
if task.task_id not in dependencies or not dependencies[task.task_id]:
|
|
566
|
+
required.update(task.inputs)
|
|
567
|
+
return required
|