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
attune/mcp/server.py CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  Exposes Empathy workflows as MCP tools for Claude Code integration.
4
4
  """
5
+
5
6
  import asyncio
6
7
  import json
7
8
  import logging
@@ -39,11 +40,11 @@ class EmpathyMCPServer:
39
40
  "properties": {
40
41
  "path": {
41
42
  "type": "string",
42
- "description": "Path to directory or file to audit"
43
+ "description": "Path to directory or file to audit",
43
44
  }
44
45
  },
45
- "required": ["path"]
46
- }
46
+ "required": ["path"],
47
+ },
47
48
  },
48
49
  "bug_predict": {
49
50
  "name": "bug_predict",
@@ -53,11 +54,11 @@ class EmpathyMCPServer:
53
54
  "properties": {
54
55
  "path": {
55
56
  "type": "string",
56
- "description": "Path to directory or file to analyze"
57
+ "description": "Path to directory or file to analyze",
57
58
  }
58
59
  },
59
- "required": ["path"]
60
- }
60
+ "required": ["path"],
61
+ },
61
62
  },
62
63
  "code_review": {
63
64
  "name": "code_review",
@@ -67,11 +68,11 @@ class EmpathyMCPServer:
67
68
  "properties": {
68
69
  "path": {
69
70
  "type": "string",
70
- "description": "Path to directory or file to review"
71
+ "description": "Path to directory or file to review",
71
72
  }
72
73
  },
73
- "required": ["path"]
74
- }
74
+ "required": ["path"],
75
+ },
75
76
  },
76
77
  "test_generation": {
77
78
  "name": "test_generation",
@@ -79,18 +80,15 @@ class EmpathyMCPServer:
79
80
  "input_schema": {
80
81
  "type": "object",
81
82
  "properties": {
82
- "module": {
83
- "type": "string",
84
- "description": "Path to Python module"
85
- },
83
+ "module": {"type": "string", "description": "Path to Python module"},
86
84
  "batch": {
87
85
  "type": "boolean",
88
86
  "description": "Enable batch mode for parallel generation",
89
- "default": False
90
- }
87
+ "default": False,
88
+ },
91
89
  },
92
- "required": ["module"]
93
- }
90
+ "required": ["module"],
91
+ },
94
92
  },
95
93
  "performance_audit": {
96
94
  "name": "performance_audit",
@@ -100,11 +98,11 @@ class EmpathyMCPServer:
100
98
  "properties": {
101
99
  "path": {
102
100
  "type": "string",
103
- "description": "Path to directory or file to audit"
101
+ "description": "Path to directory or file to audit",
104
102
  }
105
103
  },
106
- "required": ["path"]
107
- }
104
+ "required": ["path"],
105
+ },
108
106
  },
109
107
  "release_prep": {
110
108
  "name": "release_prep",
@@ -115,18 +113,15 @@ class EmpathyMCPServer:
115
113
  "path": {
116
114
  "type": "string",
117
115
  "description": "Path to project root",
118
- "default": "."
116
+ "default": ".",
119
117
  }
120
- }
121
- }
118
+ },
119
+ },
122
120
  },
123
121
  "auth_status": {
124
122
  "name": "auth_status",
125
123
  "description": "Get authentication strategy status. Shows current configuration, subscription tier, and default mode.",
126
- "input_schema": {
127
- "type": "object",
128
- "properties": {}
129
- }
124
+ "input_schema": {"type": "object", "properties": {}},
130
125
  },
131
126
  "auth_recommend": {
132
127
  "name": "auth_recommend",
@@ -134,13 +129,10 @@ class EmpathyMCPServer:
134
129
  "input_schema": {
135
130
  "type": "object",
136
131
  "properties": {
137
- "file_path": {
138
- "type": "string",
139
- "description": "Path to file to analyze"
140
- }
132
+ "file_path": {"type": "string", "description": "Path to file to analyze"}
141
133
  },
142
- "required": ["file_path"]
143
- }
134
+ "required": ["file_path"],
135
+ },
144
136
  },
145
137
  "telemetry_stats": {
146
138
  "name": "telemetry_stats",
@@ -151,19 +143,16 @@ class EmpathyMCPServer:
151
143
  "days": {
152
144
  "type": "integer",
153
145
  "description": "Number of days to analyze",
154
- "default": 30
146
+ "default": 30,
155
147
  }
156
- }
157
- }
148
+ },
149
+ },
158
150
  },
159
151
  "dashboard_status": {
160
152
  "name": "dashboard_status",
161
153
  "description": "Get agent coordination dashboard status. Shows active agents, pending approvals, recent signals.",
162
- "input_schema": {
163
- "type": "object",
164
- "properties": {}
165
- }
166
- }
154
+ "input_schema": {"type": "object", "properties": {}},
155
+ },
167
156
  }
168
157
 
169
158
  def _register_resources(self) -> dict[str, dict[str, Any]]:
@@ -177,20 +166,20 @@ class EmpathyMCPServer:
177
166
  "uri": "empathy://workflows",
178
167
  "name": "Available Workflows",
179
168
  "description": "List of all available Empathy workflows",
180
- "mime_type": "application/json"
169
+ "mime_type": "application/json",
181
170
  },
182
171
  "auth_config": {
183
172
  "uri": "empathy://auth/config",
184
173
  "name": "Authentication Configuration",
185
174
  "description": "Current authentication strategy configuration",
186
- "mime_type": "application/json"
175
+ "mime_type": "application/json",
187
176
  },
188
177
  "telemetry": {
189
178
  "uri": "empathy://telemetry",
190
179
  "name": "Telemetry Data",
191
180
  "description": "Cost tracking and performance metrics",
192
- "mime_type": "application/json"
193
- }
181
+ "mime_type": "application/json",
182
+ },
194
183
  }
195
184
 
196
185
  async def call_tool(self, tool_name: str, arguments: dict[str, Any]) -> dict[str, Any]:
@@ -225,16 +214,10 @@ class EmpathyMCPServer:
225
214
  elif tool_name == "dashboard_status":
226
215
  return await self._get_dashboard_status()
227
216
  else:
228
- return {
229
- "success": False,
230
- "error": f"Unknown tool: {tool_name}"
231
- }
217
+ return {"success": False, "error": f"Unknown tool: {tool_name}"}
232
218
  except Exception as e:
233
219
  logger.exception(f"Tool execution failed: {tool_name}")
234
- return {
235
- "success": False,
236
- "error": str(e)
237
- }
220
+ return {"success": False, "error": str(e)}
238
221
 
239
222
  async def _run_security_audit(self, args: dict[str, Any]) -> dict[str, Any]:
240
223
  """Run security audit workflow."""
@@ -248,7 +231,7 @@ class EmpathyMCPServer:
248
231
  "score": result.final_output.get("health_score"),
249
232
  "findings": result.final_output.get("findings", []),
250
233
  "cost": result.cost_report.total_cost,
251
- "provider": result.provider
234
+ "provider": result.provider,
252
235
  }
253
236
 
254
237
  async def _run_bug_predict(self, args: dict[str, Any]) -> dict[str, Any]:
@@ -261,7 +244,7 @@ class EmpathyMCPServer:
261
244
  return {
262
245
  "success": result.success,
263
246
  "predictions": result.final_output.get("predictions", []),
264
- "cost": result.cost_report.total_cost
247
+ "cost": result.cost_report.total_cost,
265
248
  }
266
249
 
267
250
  async def _run_code_review(self, args: dict[str, Any]) -> dict[str, Any]:
@@ -275,7 +258,7 @@ class EmpathyMCPServer:
275
258
  "success": result.success,
276
259
  "feedback": result.final_output.get("feedback"),
277
260
  "score": result.final_output.get("quality_score"),
278
- "cost": result.cost_report.total_cost
261
+ "cost": result.cost_report.total_cost,
279
262
  }
280
263
 
281
264
  async def _run_test_generation(self, args: dict[str, Any]) -> dict[str, Any]:
@@ -289,7 +272,7 @@ class EmpathyMCPServer:
289
272
  "success": result.success,
290
273
  "tests_generated": result.final_output.get("tests_generated", 0),
291
274
  "output_path": result.final_output.get("output_path"),
292
- "cost": result.cost_report.total_cost
275
+ "cost": result.cost_report.total_cost,
293
276
  }
294
277
 
295
278
  async def _run_performance_audit(self, args: dict[str, Any]) -> dict[str, Any]:
@@ -303,7 +286,7 @@ class EmpathyMCPServer:
303
286
  "success": result.success,
304
287
  "findings": result.final_output.get("findings", []),
305
288
  "score": result.final_output.get("score"),
306
- "cost": result.cost_report.total_cost
289
+ "cost": result.cost_report.total_cost,
307
290
  }
308
291
 
309
292
  async def _run_release_prep(self, args: dict[str, Any]) -> dict[str, Any]:
@@ -318,7 +301,7 @@ class EmpathyMCPServer:
318
301
  "approved": result.final_output.get("approved"),
319
302
  "health_score": result.final_output.get("health_score"),
320
303
  "recommendation": result.final_output.get("recommendation"),
321
- "cost": result.cost_report.total_cost
304
+ "cost": result.cost_report.total_cost,
322
305
  }
323
306
 
324
307
  async def _get_auth_status(self) -> dict[str, Any]:
@@ -331,7 +314,7 @@ class EmpathyMCPServer:
331
314
  "success": True,
332
315
  "subscription_tier": strategy.subscription_tier.value,
333
316
  "default_mode": strategy.default_mode.value,
334
- "setup_completed": strategy.setup_completed
317
+ "setup_completed": strategy.setup_completed,
335
318
  }
336
319
 
337
320
  async def _get_auth_recommend(self, args: dict[str, Any]) -> dict[str, Any]:
@@ -356,7 +339,7 @@ class EmpathyMCPServer:
356
339
  "file_path": str(file_path),
357
340
  "lines_of_code": lines,
358
341
  "category": category,
359
- "recommended_mode": recommended.value
342
+ "recommended_mode": recommended.value,
360
343
  }
361
344
 
362
345
  async def _get_telemetry_stats(self, args: dict[str, Any]) -> dict[str, Any]:
@@ -367,18 +350,13 @@ class EmpathyMCPServer:
367
350
  "days": args.get("days", 30),
368
351
  "total_cost": 0.0,
369
352
  "savings": 0.0,
370
- "cache_hit_rate": 0.0
353
+ "cache_hit_rate": 0.0,
371
354
  }
372
355
 
373
356
  async def _get_dashboard_status(self) -> dict[str, Any]:
374
357
  """Get dashboard status."""
375
358
  # Placeholder - would integrate with actual dashboard
376
- return {
377
- "success": True,
378
- "active_agents": 0,
379
- "pending_approvals": 0,
380
- "recent_signals": 0
381
- }
359
+ return {"success": True, "active_agents": 0, "pending_approvals": 0, "recent_signals": 0}
382
360
 
383
361
  def get_tool_list(self) -> list[dict[str, Any]]:
384
362
  """Get list of available tools.
@@ -411,32 +389,16 @@ async def handle_request(server: EmpathyMCPServer, request: dict[str, Any]) -> d
411
389
  params = request.get("params", {})
412
390
 
413
391
  if method == "tools/list":
414
- return {
415
- "tools": server.get_tool_list()
416
- }
392
+ return {"tools": server.get_tool_list()}
417
393
  elif method == "tools/call":
418
394
  tool_name = params.get("name")
419
395
  arguments = params.get("arguments", {})
420
396
  result = await server.call_tool(tool_name, arguments)
421
- return {
422
- "content": [
423
- {
424
- "type": "text",
425
- "text": json.dumps(result, indent=2)
426
- }
427
- ]
428
- }
397
+ return {"content": [{"type": "text", "text": json.dumps(result, indent=2)}]}
429
398
  elif method == "resources/list":
430
- return {
431
- "resources": server.get_resource_list()
432
- }
399
+ return {"resources": server.get_resource_list()}
433
400
  else:
434
- return {
435
- "error": {
436
- "code": -32601,
437
- "message": f"Method not found: {method}"
438
- }
439
- }
401
+ return {"error": {"code": -32601, "message": f"Method not found: {method}"}}
440
402
 
441
403
 
442
404
  async def main_loop():
@@ -461,21 +423,11 @@ async def main_loop():
461
423
 
462
424
  except json.JSONDecodeError as e:
463
425
  logger.error(f"Invalid JSON: {e}")
464
- error_response = {
465
- "error": {
466
- "code": -32700,
467
- "message": "Parse error"
468
- }
469
- }
426
+ error_response = {"error": {"code": -32700, "message": "Parse error"}}
470
427
  print(json.dumps(error_response), flush=True)
471
428
  except Exception as e:
472
429
  logger.exception("Error handling request")
473
- error_response = {
474
- "error": {
475
- "code": -32603,
476
- "message": str(e)
477
- }
478
- }
430
+ error_response = {"error": {"code": -32603, "message": str(e)}}
479
431
  print(json.dumps(error_response), flush=True)
480
432
 
481
433
 
@@ -492,8 +444,8 @@ def main():
492
444
  """Entry point for MCP server."""
493
445
  logging.basicConfig(
494
446
  level=logging.INFO,
495
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
496
- handlers=[logging.FileHandler('/tmp/empathy-mcp.log')]
447
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
448
+ handlers=[logging.FileHandler("/tmp/empathy-mcp.log")],
497
449
  )
498
450
 
499
451
  try:
@@ -886,8 +886,6 @@ class SecureMemDocsIntegration:
886
886
  # ============================================================================
887
887
 
888
888
 
889
-
890
-
891
889
  # ============================================================================
892
890
  # Backward Compatibility Exports
893
891
  # ============================================================================
@@ -0,0 +1,84 @@
1
+ """Short-term memory module - Refactored modular structure.
2
+
3
+ This package provides Redis-backed short-term memory for the Attune framework.
4
+ The RedisShortTermMemory class is a facade that composes functionality from
5
+ specialized submodules.
6
+
7
+ Submodules:
8
+ base: Core CRUD operations and connection management
9
+ caching: Local LRU cache layer
10
+ security: PII scrubbing and secrets detection
11
+ working: Working memory (stash/retrieve)
12
+ patterns: Pattern staging workflow
13
+ conflicts: Conflict negotiation
14
+ sessions: Collaboration session management
15
+ batch: Batch operations for efficiency
16
+ pagination: SCAN-based key pagination
17
+ pubsub: Pub/Sub messaging
18
+ streams: Redis Streams operations
19
+ timelines: Time-window queries (sorted sets)
20
+ queues: Task queue operations (lists)
21
+ transactions: Atomic operations
22
+ cross_session: Cross-session coordination
23
+
24
+ Backward Compatibility:
25
+ All original imports continue to work:
26
+ >>> from attune.memory.short_term import RedisShortTermMemory
27
+ >>> from attune.memory.short_term import RedisConfig, StagedPattern
28
+
29
+ Copyright 2025 Smart-AI-Memory
30
+ Licensed under Fair Source License 0.9
31
+ """
32
+
33
+ # Phase 8 Complete: Import from facade module
34
+ # The facade composes all 15 specialized submodules into a single class
35
+ # that maintains full backward compatibility with the original API.
36
+
37
+ # Import the main class from the facade module
38
+ from attune.memory.short_term.facade import (
39
+ REDIS_AVAILABLE,
40
+ RedisShortTermMemory,
41
+ logger,
42
+ )
43
+
44
+ # Re-export redis module for test patching compatibility
45
+ try:
46
+ import redis
47
+ except ImportError:
48
+ redis = None # type: ignore
49
+
50
+ # Import all public types from the types module (used by the implementation)
51
+ from attune.memory.types import (
52
+ AccessTier,
53
+ AgentCredentials,
54
+ ConflictContext,
55
+ PaginatedResult,
56
+ RedisConfig,
57
+ RedisMetrics,
58
+ SecurityError,
59
+ StagedPattern,
60
+ TimeWindowQuery,
61
+ TTLStrategy,
62
+ )
63
+
64
+ __all__ = [
65
+ # Main class
66
+ "RedisShortTermMemory",
67
+ # Constants
68
+ "REDIS_AVAILABLE",
69
+ # Configuration
70
+ "RedisConfig",
71
+ "RedisMetrics",
72
+ # Dataclasses
73
+ "StagedPattern",
74
+ "ConflictContext",
75
+ "AgentCredentials",
76
+ # Enums
77
+ "AccessTier",
78
+ "TTLStrategy",
79
+ # Query types
80
+ "TimeWindowQuery",
81
+ "PaginatedResult",
82
+ # Errors
83
+ "SecurityError",
84
+ ]