attune-ai 2.1.4__py3-none-any.whl → 2.2.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 (123) hide show
  1. attune/cli/__init__.py +3 -55
  2. attune/cli/commands/batch.py +4 -12
  3. attune/cli/commands/cache.py +7 -15
  4. attune/cli/commands/provider.py +17 -0
  5. attune/cli/commands/routing.py +3 -1
  6. attune/cli/commands/setup.py +122 -0
  7. attune/cli/commands/tier.py +1 -3
  8. attune/cli/commands/workflow.py +31 -0
  9. attune/cli/parsers/cache.py +1 -0
  10. attune/cli/parsers/help.py +1 -3
  11. attune/cli/parsers/provider.py +7 -0
  12. attune/cli/parsers/routing.py +1 -3
  13. attune/cli/parsers/setup.py +7 -0
  14. attune/cli/parsers/status.py +1 -3
  15. attune/cli/parsers/tier.py +1 -3
  16. attune/cli_minimal.py +34 -28
  17. attune/cli_router.py +9 -7
  18. attune/cli_unified.py +3 -0
  19. attune/core.py +190 -0
  20. attune/dashboard/app.py +4 -2
  21. attune/dashboard/simple_server.py +3 -1
  22. attune/dashboard/standalone_server.py +7 -3
  23. attune/mcp/server.py +54 -102
  24. attune/memory/long_term.py +0 -2
  25. attune/memory/short_term/__init__.py +84 -0
  26. attune/memory/short_term/base.py +467 -0
  27. attune/memory/short_term/batch.py +219 -0
  28. attune/memory/short_term/caching.py +227 -0
  29. attune/memory/short_term/conflicts.py +265 -0
  30. attune/memory/short_term/cross_session.py +122 -0
  31. attune/memory/short_term/facade.py +655 -0
  32. attune/memory/short_term/pagination.py +215 -0
  33. attune/memory/short_term/patterns.py +271 -0
  34. attune/memory/short_term/pubsub.py +286 -0
  35. attune/memory/short_term/queues.py +244 -0
  36. attune/memory/short_term/security.py +300 -0
  37. attune/memory/short_term/sessions.py +250 -0
  38. attune/memory/short_term/streams.py +249 -0
  39. attune/memory/short_term/timelines.py +234 -0
  40. attune/memory/short_term/transactions.py +186 -0
  41. attune/memory/short_term/working.py +252 -0
  42. attune/meta_workflows/cli_commands/__init__.py +3 -0
  43. attune/meta_workflows/cli_commands/agent_commands.py +0 -4
  44. attune/meta_workflows/cli_commands/analytics_commands.py +0 -6
  45. attune/meta_workflows/cli_commands/config_commands.py +0 -5
  46. attune/meta_workflows/cli_commands/memory_commands.py +0 -5
  47. attune/meta_workflows/cli_commands/template_commands.py +0 -5
  48. attune/meta_workflows/cli_commands/workflow_commands.py +0 -6
  49. attune/meta_workflows/workflow.py +1 -1
  50. attune/models/adaptive_routing.py +4 -8
  51. attune/models/auth_cli.py +3 -9
  52. attune/models/auth_strategy.py +2 -4
  53. attune/models/provider_config.py +20 -1
  54. attune/models/telemetry/analytics.py +0 -2
  55. attune/models/telemetry/backend.py +0 -3
  56. attune/models/telemetry/storage.py +0 -2
  57. attune/orchestration/_strategies/__init__.py +156 -0
  58. attune/orchestration/_strategies/base.py +231 -0
  59. attune/orchestration/_strategies/conditional_strategies.py +373 -0
  60. attune/orchestration/_strategies/conditions.py +369 -0
  61. attune/orchestration/_strategies/core_strategies.py +491 -0
  62. attune/orchestration/_strategies/data_classes.py +64 -0
  63. attune/orchestration/_strategies/nesting.py +233 -0
  64. attune/orchestration/execution_strategies.py +58 -1567
  65. attune/orchestration/meta_orchestrator.py +1 -3
  66. attune/project_index/scanner.py +1 -3
  67. attune/project_index/scanner_parallel.py +7 -5
  68. attune/socratic_router.py +1 -3
  69. attune/telemetry/agent_coordination.py +9 -3
  70. attune/telemetry/agent_tracking.py +16 -3
  71. attune/telemetry/approval_gates.py +22 -5
  72. attune/telemetry/cli.py +3 -3
  73. attune/telemetry/commands/dashboard_commands.py +24 -8
  74. attune/telemetry/event_streaming.py +8 -2
  75. attune/telemetry/feedback_loop.py +10 -2
  76. attune/tools.py +1 -0
  77. attune/workflow_commands.py +1 -3
  78. attune/workflows/__init__.py +53 -10
  79. attune/workflows/autonomous_test_gen.py +160 -104
  80. attune/workflows/base.py +48 -664
  81. attune/workflows/batch_processing.py +2 -4
  82. attune/workflows/compat.py +156 -0
  83. attune/workflows/cost_mixin.py +141 -0
  84. attune/workflows/data_classes.py +92 -0
  85. attune/workflows/document_gen/workflow.py +11 -14
  86. attune/workflows/history.py +62 -37
  87. attune/workflows/llm_base.py +2 -4
  88. attune/workflows/migration.py +422 -0
  89. attune/workflows/output.py +3 -9
  90. attune/workflows/parsing_mixin.py +427 -0
  91. attune/workflows/perf_audit.py +3 -1
  92. attune/workflows/progress.py +10 -13
  93. attune/workflows/release_prep.py +5 -1
  94. attune/workflows/routing.py +0 -2
  95. attune/workflows/secure_release.py +2 -1
  96. attune/workflows/security_audit.py +19 -14
  97. attune/workflows/security_audit_phase3.py +28 -22
  98. attune/workflows/seo_optimization.py +29 -29
  99. attune/workflows/test_gen/test_templates.py +1 -4
  100. attune/workflows/test_gen/workflow.py +0 -2
  101. attune/workflows/test_gen_behavioral.py +7 -20
  102. attune/workflows/test_gen_parallel.py +6 -4
  103. {attune_ai-2.1.4.dist-info → attune_ai-2.2.0.dist-info}/METADATA +4 -3
  104. {attune_ai-2.1.4.dist-info → attune_ai-2.2.0.dist-info}/RECORD +119 -94
  105. {attune_ai-2.1.4.dist-info → attune_ai-2.2.0.dist-info}/entry_points.txt +0 -2
  106. attune_healthcare/monitors/monitoring/__init__.py +9 -9
  107. attune_llm/agent_factory/__init__.py +6 -6
  108. attune_llm/commands/__init__.py +10 -10
  109. attune_llm/commands/models.py +3 -3
  110. attune_llm/config/__init__.py +8 -8
  111. attune_llm/learning/__init__.py +3 -3
  112. attune_llm/learning/extractor.py +5 -3
  113. attune_llm/learning/storage.py +5 -3
  114. attune_llm/security/__init__.py +17 -17
  115. attune_llm/utils/tokens.py +3 -1
  116. attune/cli_legacy.py +0 -3957
  117. attune/memory/short_term.py +0 -2192
  118. attune/workflows/manage_docs.py +0 -87
  119. attune/workflows/test5.py +0 -125
  120. {attune_ai-2.1.4.dist-info → attune_ai-2.2.0.dist-info}/WHEEL +0 -0
  121. {attune_ai-2.1.4.dist-info → attune_ai-2.2.0.dist-info}/licenses/LICENSE +0 -0
  122. {attune_ai-2.1.4.dist-info → attune_ai-2.2.0.dist-info}/licenses/LICENSE_CHANGE_ANNOUNCEMENT.md +0 -0
  123. {attune_ai-2.1.4.dist-info → attune_ai-2.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,156 @@
1
+ """Execution strategies for agent composition patterns.
2
+
3
+ This submodule implements the grammar rules for composing agents:
4
+ 1. Sequential (A → B → C)
5
+ 2. Parallel (A || B || C)
6
+ 3. Debate (A ⇄ B ⇄ C → Synthesis)
7
+ 4. Teaching (Junior → Expert validation)
8
+ 5. Refinement (Draft → Review → Polish)
9
+ 6. Adaptive (Classifier → Specialist)
10
+ 7. Conditional (if X then A else B) - branching based on gates
11
+
12
+ This package provides modular organization of execution strategies:
13
+ - data_classes: AgentResult, StrategyResult
14
+ - conditions: ConditionType, Condition, Branch, ConditionEvaluator
15
+ - nesting: WorkflowReference, InlineWorkflow, NestingContext, WorkflowDefinition
16
+ - base: ExecutionStrategy ABC
17
+ - core_strategies: Sequential, Parallel, Debate, Teaching, Refinement, Adaptive
18
+ - conditional_strategies: Conditional, MultiConditional, Nested, NestedSequential
19
+ - advanced: ToolEnhanced, PromptCached, etc. (TODO)
20
+
21
+ Copyright 2025 Smart-AI-Memory
22
+ Licensed under Fair Source License 0.9
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ # Base strategy class
28
+ from .base import ExecutionStrategy
29
+
30
+ # Conditional and nested strategies
31
+ from .conditional_strategies import (
32
+ ConditionalStrategy,
33
+ MultiConditionalStrategy,
34
+ NestedSequentialStrategy,
35
+ NestedStrategy,
36
+ StepDefinition,
37
+ )
38
+
39
+ # Condition types and evaluator
40
+ from .conditions import Branch, Condition, ConditionEvaluator, ConditionType
41
+
42
+ # Core strategies
43
+ from .core_strategies import (
44
+ AdaptiveStrategy,
45
+ DebateStrategy,
46
+ ParallelStrategy,
47
+ RefinementStrategy,
48
+ SequentialStrategy,
49
+ TeachingStrategy,
50
+ )
51
+
52
+ # Data classes
53
+ from .data_classes import AgentResult, StrategyResult
54
+
55
+ # Nesting support
56
+ from .nesting import (
57
+ WORKFLOW_REGISTRY,
58
+ InlineWorkflow,
59
+ NestingContext,
60
+ WorkflowDefinition,
61
+ WorkflowReference,
62
+ get_workflow,
63
+ register_workflow,
64
+ )
65
+
66
+ # Strategy registry for lookup by name (partial - advanced strategies added in main module)
67
+ _STRATEGY_REGISTRY: dict[str, type[ExecutionStrategy]] = {
68
+ # Core patterns (1-6)
69
+ "sequential": SequentialStrategy,
70
+ "parallel": ParallelStrategy,
71
+ "debate": DebateStrategy,
72
+ "teaching": TeachingStrategy,
73
+ "refinement": RefinementStrategy,
74
+ "adaptive": AdaptiveStrategy,
75
+ # Conditional patterns (7+)
76
+ "conditional": ConditionalStrategy,
77
+ "multi_conditional": MultiConditionalStrategy,
78
+ "nested": NestedStrategy,
79
+ "nested_sequential": NestedSequentialStrategy,
80
+ }
81
+
82
+
83
+ def get_strategy(strategy_name: str) -> ExecutionStrategy:
84
+ """Get strategy instance by name.
85
+
86
+ Args:
87
+ strategy_name: Strategy name (e.g., "sequential", "parallel")
88
+
89
+ Returns:
90
+ ExecutionStrategy instance
91
+
92
+ Raises:
93
+ ValueError: If strategy name is invalid
94
+
95
+ Example:
96
+ >>> strategy = get_strategy("sequential")
97
+ >>> isinstance(strategy, SequentialStrategy)
98
+ True
99
+ """
100
+ if strategy_name not in _STRATEGY_REGISTRY:
101
+ raise ValueError(
102
+ f"Unknown strategy: {strategy_name}. Available: {list(_STRATEGY_REGISTRY.keys())}"
103
+ )
104
+
105
+ strategy_class = _STRATEGY_REGISTRY[strategy_name]
106
+ return strategy_class()
107
+
108
+
109
+ def register_strategy(name: str, strategy_class: type[ExecutionStrategy]) -> None:
110
+ """Register a strategy class by name.
111
+
112
+ Used by main module to add advanced strategies.
113
+
114
+ Args:
115
+ name: Strategy name
116
+ strategy_class: Strategy class
117
+ """
118
+ _STRATEGY_REGISTRY[name] = strategy_class
119
+
120
+
121
+ __all__ = [
122
+ # Data classes
123
+ "AgentResult",
124
+ "StrategyResult",
125
+ # Conditions
126
+ "Branch",
127
+ "Condition",
128
+ "ConditionEvaluator",
129
+ "ConditionType",
130
+ # Nesting
131
+ "InlineWorkflow",
132
+ "NestingContext",
133
+ "WORKFLOW_REGISTRY",
134
+ "WorkflowDefinition",
135
+ "WorkflowReference",
136
+ "get_workflow",
137
+ "register_workflow",
138
+ # Base strategy
139
+ "ExecutionStrategy",
140
+ # Core strategies
141
+ "AdaptiveStrategy",
142
+ "DebateStrategy",
143
+ "ParallelStrategy",
144
+ "RefinementStrategy",
145
+ "SequentialStrategy",
146
+ "TeachingStrategy",
147
+ # Conditional strategies
148
+ "ConditionalStrategy",
149
+ "MultiConditionalStrategy",
150
+ "NestedSequentialStrategy",
151
+ "NestedStrategy",
152
+ "StepDefinition",
153
+ # Functions
154
+ "get_strategy",
155
+ "register_strategy",
156
+ ]
@@ -0,0 +1,231 @@
1
+ """Base class for agent composition strategies.
2
+
3
+ This module defines the ExecutionStrategy abstract base class that all
4
+ strategy implementations must inherit from.
5
+
6
+ Security:
7
+ - All agent outputs validated before passing to next agent
8
+ - No eval() or exec() usage
9
+ - Timeout enforcement at strategy level
10
+
11
+ Copyright 2025 Smart-AI-Memory
12
+ Licensed under Fair Source License 0.9
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ from abc import ABC, abstractmethod
19
+ from typing import TYPE_CHECKING, Any
20
+
21
+ from .data_classes import AgentResult, StrategyResult
22
+
23
+ if TYPE_CHECKING:
24
+ from ..agent_templates import AgentTemplate
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ class ExecutionStrategy(ABC):
30
+ """Base class for agent composition strategies.
31
+
32
+ All strategies must implement execute() method to define
33
+ how agents are coordinated and results aggregated.
34
+ """
35
+
36
+ @abstractmethod
37
+ async def execute(
38
+ self, agents: list[AgentTemplate], context: dict[str, Any]
39
+ ) -> StrategyResult:
40
+ """Execute agents using this strategy.
41
+
42
+ Args:
43
+ agents: List of agent templates to execute
44
+ context: Initial context for execution
45
+
46
+ Returns:
47
+ StrategyResult with aggregated outputs
48
+
49
+ Raises:
50
+ ValueError: If agents list is empty
51
+ TimeoutError: If execution exceeds timeout
52
+ """
53
+ pass
54
+
55
+ async def _execute_agent(
56
+ self, agent: AgentTemplate, context: dict[str, Any]
57
+ ) -> AgentResult:
58
+ """Execute a single agent with real analysis tools.
59
+
60
+ Maps agent capabilities to real tool implementations and executes them.
61
+
62
+ Args:
63
+ agent: Agent template to execute
64
+ context: Execution context
65
+
66
+ Returns:
67
+ AgentResult with execution outcome
68
+ """
69
+ import time
70
+
71
+ from ..real_tools import (
72
+ RealCodeQualityAnalyzer,
73
+ RealCoverageAnalyzer,
74
+ RealDocumentationAnalyzer,
75
+ RealSecurityAuditor,
76
+ )
77
+
78
+ logger.info(f"Executing agent: {agent.id} ({agent.role})")
79
+ start_time = time.perf_counter()
80
+
81
+ # Get project root from context
82
+ project_root = context.get("project_root", ".")
83
+ target_path = context.get("target_path", "src")
84
+
85
+ try:
86
+ # Map agent ID to real tool implementation
87
+ if agent.id == "security_auditor" or "security" in agent.role.lower():
88
+ auditor = RealSecurityAuditor(project_root)
89
+ report = auditor.audit(target_path)
90
+
91
+ output = {
92
+ "agent_role": agent.role,
93
+ "total_issues": report.total_issues,
94
+ "critical_issues": report.critical_count, # Match workflow field name
95
+ "high_issues": report.high_count, # Match workflow field name
96
+ "medium_issues": report.medium_count, # Match workflow field name
97
+ "passed": report.passed,
98
+ "issues_by_file": report.issues_by_file,
99
+ }
100
+ success = report.passed
101
+ confidence = 1.0 if report.total_issues == 0 else 0.7
102
+
103
+ elif agent.id == "test_coverage_analyzer" or "coverage" in agent.role.lower():
104
+ analyzer = RealCoverageAnalyzer(project_root)
105
+ report = analyzer.analyze() # Analyzes all packages automatically
106
+
107
+ output = {
108
+ "agent_role": agent.role,
109
+ "coverage_percent": report.total_coverage, # Match workflow field name
110
+ "total_coverage": report.total_coverage, # Keep for compatibility
111
+ "files_analyzed": report.files_analyzed,
112
+ "uncovered_files": report.uncovered_files,
113
+ "passed": report.total_coverage >= 80.0,
114
+ }
115
+ success = report.total_coverage >= 80.0
116
+ confidence = min(report.total_coverage / 100.0, 1.0)
117
+
118
+ elif agent.id == "code_reviewer" or "quality" in agent.role.lower():
119
+ analyzer = RealCodeQualityAnalyzer(project_root)
120
+ report = analyzer.analyze(target_path)
121
+
122
+ output = {
123
+ "agent_role": agent.role,
124
+ "quality_score": report.quality_score,
125
+ "ruff_issues": report.ruff_issues,
126
+ "mypy_issues": report.mypy_issues,
127
+ "total_files": report.total_files,
128
+ "passed": report.passed,
129
+ }
130
+ success = report.passed
131
+ confidence = report.quality_score / 10.0
132
+
133
+ elif agent.id == "documentation_writer" or "documentation" in agent.role.lower():
134
+ analyzer = RealDocumentationAnalyzer(project_root)
135
+ report = analyzer.analyze(target_path)
136
+
137
+ output = {
138
+ "agent_role": agent.role,
139
+ "completeness": report.completeness_percentage,
140
+ "coverage_percent": report.completeness_percentage, # Match Release Prep field name
141
+ "total_functions": report.total_functions,
142
+ "documented_functions": report.documented_functions,
143
+ "total_classes": report.total_classes,
144
+ "documented_classes": report.documented_classes,
145
+ "missing_docstrings": report.missing_docstrings,
146
+ "passed": report.passed,
147
+ }
148
+ success = report.passed
149
+ confidence = report.completeness_percentage / 100.0
150
+
151
+ elif agent.id == "performance_optimizer" or "performance" in agent.role.lower():
152
+ # Performance analysis placeholder - mark as passed for now
153
+ # TODO: Implement real performance profiling
154
+ logger.warning("Performance analysis not yet implemented, returning placeholder")
155
+ output = {
156
+ "agent_role": agent.role,
157
+ "message": "Performance analysis not yet implemented",
158
+ "passed": True,
159
+ "placeholder": True,
160
+ }
161
+ success = True
162
+ confidence = 1.0
163
+
164
+ elif agent.id == "test_generator":
165
+ # Test generation requires different handling (LLM-based)
166
+ logger.info("Test generation requires manual invocation, returning placeholder")
167
+ output = {
168
+ "agent_role": agent.role,
169
+ "message": "Test generation requires manual invocation",
170
+ "passed": True,
171
+ }
172
+ success = True
173
+ confidence = 0.8
174
+
175
+ else:
176
+ # Unknown agent type - log warning and return placeholder
177
+ logger.warning(f"Unknown agent type: {agent.id}, returning placeholder")
178
+ output = {
179
+ "agent_role": agent.role,
180
+ "agent_id": agent.id,
181
+ "message": "Unknown agent type - no real implementation",
182
+ "passed": True,
183
+ }
184
+ success = True
185
+ confidence = 0.5
186
+
187
+ duration = time.perf_counter() - start_time
188
+
189
+ logger.info(
190
+ f"Agent {agent.id} completed: success={success}, "
191
+ f"confidence={confidence:.2f}, duration={duration:.2f}s"
192
+ )
193
+
194
+ return AgentResult(
195
+ agent_id=agent.id,
196
+ success=success,
197
+ output=output,
198
+ confidence=confidence,
199
+ duration_seconds=duration,
200
+ )
201
+
202
+ except Exception as e:
203
+ duration = time.perf_counter() - start_time
204
+ logger.error(f"Agent {agent.id} failed: {e}")
205
+
206
+ return AgentResult(
207
+ agent_id=agent.id,
208
+ success=False,
209
+ output={"agent_role": agent.role, "error_details": str(e)},
210
+ error=str(e),
211
+ confidence=0.0,
212
+ duration_seconds=duration,
213
+ )
214
+
215
+ def _aggregate_results(self, results: list[AgentResult]) -> dict[str, Any]:
216
+ """Aggregate results from multiple agents.
217
+
218
+ Args:
219
+ results: List of agent results
220
+
221
+ Returns:
222
+ Aggregated output dictionary
223
+ """
224
+ return {
225
+ "num_agents": len(results),
226
+ "all_succeeded": all(r.success for r in results),
227
+ "avg_confidence": (
228
+ sum(r.confidence for r in results) / len(results) if results else 0.0
229
+ ),
230
+ "outputs": [r.output for r in results],
231
+ }