aiecs 1.0.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.

Potentially problematic release.


This version of aiecs might be problematic. Click here for more details.

Files changed (90) hide show
  1. aiecs/__init__.py +75 -0
  2. aiecs/__main__.py +41 -0
  3. aiecs/aiecs_client.py +295 -0
  4. aiecs/application/__init__.py +10 -0
  5. aiecs/application/executors/__init__.py +10 -0
  6. aiecs/application/executors/operation_executor.py +341 -0
  7. aiecs/config/__init__.py +15 -0
  8. aiecs/config/config.py +117 -0
  9. aiecs/config/registry.py +19 -0
  10. aiecs/core/__init__.py +46 -0
  11. aiecs/core/interface/__init__.py +34 -0
  12. aiecs/core/interface/execution_interface.py +150 -0
  13. aiecs/core/interface/storage_interface.py +214 -0
  14. aiecs/domain/__init__.py +20 -0
  15. aiecs/domain/context/__init__.py +28 -0
  16. aiecs/domain/context/content_engine.py +982 -0
  17. aiecs/domain/context/conversation_models.py +306 -0
  18. aiecs/domain/execution/__init__.py +12 -0
  19. aiecs/domain/execution/model.py +49 -0
  20. aiecs/domain/task/__init__.py +13 -0
  21. aiecs/domain/task/dsl_processor.py +460 -0
  22. aiecs/domain/task/model.py +50 -0
  23. aiecs/domain/task/task_context.py +257 -0
  24. aiecs/infrastructure/__init__.py +26 -0
  25. aiecs/infrastructure/messaging/__init__.py +13 -0
  26. aiecs/infrastructure/messaging/celery_task_manager.py +341 -0
  27. aiecs/infrastructure/messaging/websocket_manager.py +289 -0
  28. aiecs/infrastructure/monitoring/__init__.py +12 -0
  29. aiecs/infrastructure/monitoring/executor_metrics.py +138 -0
  30. aiecs/infrastructure/monitoring/structured_logger.py +50 -0
  31. aiecs/infrastructure/monitoring/tracing_manager.py +376 -0
  32. aiecs/infrastructure/persistence/__init__.py +12 -0
  33. aiecs/infrastructure/persistence/database_manager.py +286 -0
  34. aiecs/infrastructure/persistence/file_storage.py +671 -0
  35. aiecs/infrastructure/persistence/redis_client.py +162 -0
  36. aiecs/llm/__init__.py +54 -0
  37. aiecs/llm/base_client.py +99 -0
  38. aiecs/llm/client_factory.py +339 -0
  39. aiecs/llm/custom_callbacks.py +228 -0
  40. aiecs/llm/openai_client.py +125 -0
  41. aiecs/llm/vertex_client.py +186 -0
  42. aiecs/llm/xai_client.py +184 -0
  43. aiecs/main.py +351 -0
  44. aiecs/scripts/DEPENDENCY_SYSTEM_SUMMARY.md +241 -0
  45. aiecs/scripts/README_DEPENDENCY_CHECKER.md +309 -0
  46. aiecs/scripts/README_WEASEL_PATCH.md +126 -0
  47. aiecs/scripts/__init__.py +3 -0
  48. aiecs/scripts/dependency_checker.py +825 -0
  49. aiecs/scripts/dependency_fixer.py +348 -0
  50. aiecs/scripts/download_nlp_data.py +348 -0
  51. aiecs/scripts/fix_weasel_validator.py +121 -0
  52. aiecs/scripts/fix_weasel_validator.sh +82 -0
  53. aiecs/scripts/patch_weasel_library.sh +188 -0
  54. aiecs/scripts/quick_dependency_check.py +269 -0
  55. aiecs/scripts/run_weasel_patch.sh +41 -0
  56. aiecs/scripts/setup_nlp_data.sh +217 -0
  57. aiecs/tasks/__init__.py +2 -0
  58. aiecs/tasks/worker.py +111 -0
  59. aiecs/tools/__init__.py +196 -0
  60. aiecs/tools/base_tool.py +202 -0
  61. aiecs/tools/langchain_adapter.py +361 -0
  62. aiecs/tools/task_tools/__init__.py +82 -0
  63. aiecs/tools/task_tools/chart_tool.py +704 -0
  64. aiecs/tools/task_tools/classfire_tool.py +901 -0
  65. aiecs/tools/task_tools/image_tool.py +397 -0
  66. aiecs/tools/task_tools/office_tool.py +600 -0
  67. aiecs/tools/task_tools/pandas_tool.py +565 -0
  68. aiecs/tools/task_tools/report_tool.py +499 -0
  69. aiecs/tools/task_tools/research_tool.py +363 -0
  70. aiecs/tools/task_tools/scraper_tool.py +548 -0
  71. aiecs/tools/task_tools/search_api.py +7 -0
  72. aiecs/tools/task_tools/stats_tool.py +513 -0
  73. aiecs/tools/temp_file_manager.py +126 -0
  74. aiecs/tools/tool_executor/__init__.py +35 -0
  75. aiecs/tools/tool_executor/tool_executor.py +518 -0
  76. aiecs/utils/LLM_output_structor.py +409 -0
  77. aiecs/utils/__init__.py +23 -0
  78. aiecs/utils/base_callback.py +50 -0
  79. aiecs/utils/execution_utils.py +158 -0
  80. aiecs/utils/logging.py +1 -0
  81. aiecs/utils/prompt_loader.py +13 -0
  82. aiecs/utils/token_usage_repository.py +279 -0
  83. aiecs/ws/__init__.py +0 -0
  84. aiecs/ws/socket_server.py +41 -0
  85. aiecs-1.0.0.dist-info/METADATA +610 -0
  86. aiecs-1.0.0.dist-info/RECORD +90 -0
  87. aiecs-1.0.0.dist-info/WHEEL +5 -0
  88. aiecs-1.0.0.dist-info/entry_points.txt +7 -0
  89. aiecs-1.0.0.dist-info/licenses/LICENSE +225 -0
  90. aiecs-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,306 @@
1
+ """
2
+ Conversation Models for ContextEngine
3
+
4
+ This module defines the data models used for agent communication and conversation isolation
5
+ within the ContextEngine. These models are specific to the context management domain.
6
+ """
7
+
8
+ import uuid
9
+ from dataclasses import dataclass, field
10
+ from typing import Dict, List, Any, Optional
11
+ from datetime import datetime
12
+
13
+
14
+ @dataclass
15
+ class ConversationParticipant:
16
+ """Represents a participant in a conversation."""
17
+ participant_id: str
18
+ participant_type: str # 'user', 'master_controller', 'agent'
19
+ participant_role: Optional[str] = None # For agents: 'writer', 'researcher', etc.
20
+ metadata: Dict[str, Any] = field(default_factory=dict)
21
+
22
+ def __post_init__(self):
23
+ """Validate participant data after initialization."""
24
+ if not self.participant_id:
25
+ raise ValueError("participant_id cannot be empty")
26
+ if not self.participant_type:
27
+ raise ValueError("participant_type cannot be empty")
28
+
29
+ # Validate participant types
30
+ valid_types = {'user', 'master_controller', 'agent'}
31
+ if self.participant_type not in valid_types:
32
+ raise ValueError(f"participant_type must be one of {valid_types}")
33
+
34
+ # For agents, role should be specified
35
+ if self.participant_type == 'agent' and not self.participant_role:
36
+ raise ValueError("participant_role is required for agent participants")
37
+
38
+
39
+ @dataclass
40
+ class ConversationSession:
41
+ """Represents an isolated conversation session between participants."""
42
+ session_id: str
43
+ participants: List[ConversationParticipant]
44
+ session_type: str # 'user_to_mc', 'mc_to_agent', 'agent_to_agent', 'user_to_agent'
45
+ created_at: datetime
46
+ last_activity: datetime
47
+ metadata: Dict[str, Any] = field(default_factory=dict)
48
+
49
+ def __post_init__(self):
50
+ """Validate session data after initialization."""
51
+ if not self.session_id:
52
+ raise ValueError("session_id cannot be empty")
53
+ if not self.participants:
54
+ raise ValueError("participants list cannot be empty")
55
+
56
+ # Validate session types
57
+ valid_session_types = {'user_to_mc', 'mc_to_agent', 'agent_to_agent', 'user_to_agent'}
58
+ if self.session_type not in valid_session_types:
59
+ raise ValueError(f"session_type must be one of {valid_session_types}")
60
+
61
+ # Validate participant count and types based on session type
62
+ self._validate_participants_for_session_type()
63
+
64
+ def _validate_participants_for_session_type(self):
65
+ """Validate that participants match the session type."""
66
+ participant_types = [p.participant_type for p in self.participants]
67
+
68
+ if self.session_type == 'user_to_mc':
69
+ expected_types = {'user', 'master_controller'}
70
+ if not expected_types.issubset(set(participant_types)):
71
+ raise ValueError(f"user_to_mc session requires user and master_controller participants")
72
+
73
+ elif self.session_type == 'mc_to_agent':
74
+ expected_types = {'master_controller', 'agent'}
75
+ if not expected_types.issubset(set(participant_types)):
76
+ raise ValueError(f"mc_to_agent session requires master_controller and agent participants")
77
+
78
+ elif self.session_type == 'agent_to_agent':
79
+ agent_count = sum(1 for p in self.participants if p.participant_type == 'agent')
80
+ if agent_count < 2:
81
+ raise ValueError(f"agent_to_agent session requires at least 2 agent participants")
82
+
83
+ elif self.session_type == 'user_to_agent':
84
+ expected_types = {'user', 'agent'}
85
+ if not expected_types.issubset(set(participant_types)):
86
+ raise ValueError(f"user_to_agent session requires user and agent participants")
87
+
88
+ def generate_session_key(self) -> str:
89
+ """Generate a unique session key for conversation isolation."""
90
+ if self.session_type == 'user_to_mc':
91
+ return self.session_id
92
+ elif self.session_type == 'mc_to_agent':
93
+ agent_role = next((p.participant_role for p in self.participants if p.participant_type == 'agent'), 'unknown')
94
+ return f"{self.session_id}_mc_to_{agent_role}"
95
+ elif self.session_type == 'agent_to_agent':
96
+ agent_roles = [p.participant_role for p in self.participants if p.participant_type == 'agent']
97
+ if len(agent_roles) >= 2:
98
+ return f"{self.session_id}_{agent_roles[0]}_to_{agent_roles[1]}"
99
+ return f"{self.session_id}_agent_to_agent"
100
+ elif self.session_type == 'user_to_agent':
101
+ agent_role = next((p.participant_role for p in self.participants if p.participant_type == 'agent'), 'unknown')
102
+ return f"{self.session_id}_user_to_{agent_role}"
103
+ else:
104
+ return self.session_id
105
+
106
+ def get_participant_by_type_and_role(self, participant_type: str, participant_role: Optional[str] = None) -> Optional[ConversationParticipant]:
107
+ """Get a participant by type and optionally by role."""
108
+ for participant in self.participants:
109
+ if participant.participant_type == participant_type:
110
+ if participant_role is None or participant.participant_role == participant_role:
111
+ return participant
112
+ return None
113
+
114
+ def update_activity(self):
115
+ """Update the last activity timestamp."""
116
+ self.last_activity = datetime.utcnow()
117
+
118
+ def to_dict(self) -> Dict[str, Any]:
119
+ """Convert to dictionary for storage."""
120
+ return {
121
+ "session_id": self.session_id,
122
+ "participants": [
123
+ {
124
+ "participant_id": p.participant_id,
125
+ "participant_type": p.participant_type,
126
+ "participant_role": p.participant_role,
127
+ "metadata": p.metadata
128
+ }
129
+ for p in self.participants
130
+ ],
131
+ "session_type": self.session_type,
132
+ "created_at": self.created_at.isoformat(),
133
+ "last_activity": self.last_activity.isoformat(),
134
+ "metadata": self.metadata
135
+ }
136
+
137
+ @classmethod
138
+ def from_dict(cls, data: Dict[str, Any]) -> 'ConversationSession':
139
+ """Create from dictionary."""
140
+ participants = [
141
+ ConversationParticipant(
142
+ participant_id=p["participant_id"],
143
+ participant_type=p["participant_type"],
144
+ participant_role=p.get("participant_role"),
145
+ metadata=p.get("metadata", {})
146
+ )
147
+ for p in data["participants"]
148
+ ]
149
+
150
+ return cls(
151
+ session_id=data["session_id"],
152
+ participants=participants,
153
+ session_type=data["session_type"],
154
+ created_at=datetime.fromisoformat(data["created_at"]),
155
+ last_activity=datetime.fromisoformat(data["last_activity"]),
156
+ metadata=data.get("metadata", {})
157
+ )
158
+
159
+
160
+ @dataclass
161
+ class AgentCommunicationMessage:
162
+ """Message for agent-to-agent or controller-to-agent communication."""
163
+ message_id: str
164
+ session_key: str
165
+ sender_id: str
166
+ sender_type: str # 'master_controller', 'agent', 'user'
167
+ sender_role: Optional[str] # For agents
168
+ recipient_id: str
169
+ recipient_type: str # 'agent', 'master_controller', 'user'
170
+ recipient_role: Optional[str] # For agents
171
+ content: str
172
+ message_type: str # 'task_assignment', 'result_report', 'collaboration_request', 'feedback', 'communication'
173
+ timestamp: datetime
174
+ metadata: Dict[str, Any] = field(default_factory=dict)
175
+
176
+ def __post_init__(self):
177
+ """Validate message data after initialization."""
178
+ if not self.message_id:
179
+ self.message_id = str(uuid.uuid4())
180
+ if not self.session_key:
181
+ raise ValueError("session_key cannot be empty")
182
+ if not self.sender_id:
183
+ raise ValueError("sender_id cannot be empty")
184
+ if not self.recipient_id:
185
+ raise ValueError("recipient_id cannot be empty")
186
+ if not self.content:
187
+ raise ValueError("content cannot be empty")
188
+
189
+ # Validate message types
190
+ valid_message_types = {
191
+ 'task_assignment', 'result_report', 'collaboration_request',
192
+ 'feedback', 'communication', 'status_update', 'error_report',
193
+ 'task_completion', 'progress_update', 'clarification_request'
194
+ }
195
+ if self.message_type not in valid_message_types:
196
+ raise ValueError(f"message_type must be one of {valid_message_types}")
197
+
198
+ def to_conversation_message_dict(self) -> Dict[str, Any]:
199
+ """Convert to format compatible with ContextEngine conversation messages."""
200
+ role = f"{self.sender_type}_{self.sender_role}" if self.sender_role else self.sender_type
201
+ return {
202
+ "role": role,
203
+ "content": self.content,
204
+ "timestamp": self.timestamp.isoformat(),
205
+ "metadata": {
206
+ **self.metadata,
207
+ "message_id": self.message_id,
208
+ "sender_id": self.sender_id,
209
+ "sender_type": self.sender_type,
210
+ "sender_role": self.sender_role,
211
+ "recipient_id": self.recipient_id,
212
+ "recipient_type": self.recipient_type,
213
+ "recipient_role": self.recipient_role,
214
+ "message_type": self.message_type
215
+ }
216
+ }
217
+
218
+ def to_dict(self) -> Dict[str, Any]:
219
+ """Convert to dictionary for storage."""
220
+ return {
221
+ "message_id": self.message_id,
222
+ "session_key": self.session_key,
223
+ "sender_id": self.sender_id,
224
+ "sender_type": self.sender_type,
225
+ "sender_role": self.sender_role,
226
+ "recipient_id": self.recipient_id,
227
+ "recipient_type": self.recipient_type,
228
+ "recipient_role": self.recipient_role,
229
+ "content": self.content,
230
+ "message_type": self.message_type,
231
+ "timestamp": self.timestamp.isoformat(),
232
+ "metadata": self.metadata
233
+ }
234
+
235
+ @classmethod
236
+ def from_dict(cls, data: Dict[str, Any]) -> 'AgentCommunicationMessage':
237
+ """Create from dictionary."""
238
+ return cls(
239
+ message_id=data["message_id"],
240
+ session_key=data["session_key"],
241
+ sender_id=data["sender_id"],
242
+ sender_type=data["sender_type"],
243
+ sender_role=data.get("sender_role"),
244
+ recipient_id=data["recipient_id"],
245
+ recipient_type=data["recipient_type"],
246
+ recipient_role=data.get("recipient_role"),
247
+ content=data["content"],
248
+ message_type=data["message_type"],
249
+ timestamp=datetime.fromisoformat(data["timestamp"]),
250
+ metadata=data.get("metadata", {})
251
+ )
252
+
253
+
254
+ # Conversation isolation utility functions
255
+
256
+ def create_session_key(session_id: str, session_type: str, participants: List[ConversationParticipant]) -> str:
257
+ """
258
+ Utility function to create session keys for conversation isolation.
259
+
260
+ Args:
261
+ session_id: Base session ID
262
+ session_type: Type of conversation
263
+ participants: List of conversation participants
264
+
265
+ Returns:
266
+ Generated session key
267
+ """
268
+ if session_type == 'user_to_mc':
269
+ return session_id
270
+ elif session_type == 'mc_to_agent':
271
+ agent_role = next((p.participant_role for p in participants if p.participant_type == 'agent'), 'unknown')
272
+ return f"{session_id}_mc_to_{agent_role}"
273
+ elif session_type == 'agent_to_agent':
274
+ agent_roles = [p.participant_role for p in participants if p.participant_type == 'agent']
275
+ if len(agent_roles) >= 2:
276
+ return f"{session_id}_{agent_roles[0]}_to_{agent_roles[1]}"
277
+ return f"{session_id}_agent_to_agent"
278
+ elif session_type == 'user_to_agent':
279
+ agent_role = next((p.participant_role for p in participants if p.participant_type == 'agent'), 'unknown')
280
+ return f"{session_id}_user_to_{agent_role}"
281
+ else:
282
+ return session_id
283
+
284
+
285
+ def validate_conversation_isolation_pattern(session_key: str, expected_pattern: str) -> bool:
286
+ """
287
+ Validate that a session key follows the expected conversation isolation pattern.
288
+
289
+ Args:
290
+ session_key: The session key to validate
291
+ expected_pattern: Expected pattern ('user_to_mc', 'mc_to_agent', etc.)
292
+
293
+ Returns:
294
+ True if the pattern matches, False otherwise
295
+ """
296
+ if expected_pattern == 'user_to_mc':
297
+ # Should be just the base session_id
298
+ return '_' not in session_key or not any(x in session_key for x in ['_mc_to_', '_to_', '_user_to_'])
299
+ elif expected_pattern == 'mc_to_agent':
300
+ return '_mc_to_' in session_key
301
+ elif expected_pattern == 'agent_to_agent':
302
+ return '_to_' in session_key and '_mc_to_' not in session_key and '_user_to_' not in session_key
303
+ elif expected_pattern == 'user_to_agent':
304
+ return '_user_to_' in session_key
305
+ else:
306
+ return False
@@ -0,0 +1,12 @@
1
+ """Execution domain module
2
+
3
+ Contains execution-related business logic and models.
4
+ """
5
+
6
+ from .model import TaskStepResult, TaskStatus, ErrorCode
7
+
8
+ __all__ = [
9
+ "TaskStepResult",
10
+ "TaskStatus",
11
+ "ErrorCode",
12
+ ]
@@ -0,0 +1,49 @@
1
+ from enum import Enum
2
+ from typing import Any, Dict, Optional
3
+
4
+
5
+ class TaskStatus(Enum):
6
+ PENDING = "pending"
7
+ RUNNING = "running"
8
+ COMPLETED = "completed"
9
+ CANCELLED = "cancelled"
10
+ TIMED_OUT = "timed_out"
11
+ FAILED = "failed"
12
+
13
+
14
+ class ErrorCode(Enum):
15
+ VALIDATION_ERROR = "E001"
16
+ TIMEOUT_ERROR = "E002"
17
+ EXECUTION_ERROR = "E003"
18
+ CANCELLED_ERROR = "E004"
19
+ RETRY_EXHAUSTED = "E005"
20
+ DATABASE_ERROR = "E006"
21
+ DSL_EVALUATION_ERROR = "E007"
22
+
23
+
24
+ class TaskStepResult:
25
+ """Task step result model"""
26
+ def __init__(self, step: str, result: Any, completed: bool = False,
27
+ message: str = "", status: str = "pending",
28
+ error_code: Optional[str] = None, error_message: Optional[str] = None):
29
+ self.step = step
30
+ self.result = result
31
+ self.completed = completed
32
+ self.message = message
33
+ self.status = status
34
+ self.error_code = error_code
35
+ self.error_message = error_message
36
+
37
+ def dict(self) -> Dict[str, Any]:
38
+ return {
39
+ "step": self.step,
40
+ "result": self.result,
41
+ "completed": self.completed,
42
+ "message": self.message,
43
+ "status": self.status,
44
+ "error_code": self.error_code,
45
+ "error_message": self.error_message
46
+ }
47
+
48
+ def __repr__(self) -> str:
49
+ return f"TaskStepResult(step='{self.step}', status='{self.status}', completed={self.completed})"
@@ -0,0 +1,13 @@
1
+ """Task domain module
2
+
3
+ Contains task-related business logic and models.
4
+ """
5
+
6
+ from .model import TaskContext, DSLStep
7
+ from .dsl_processor import DSLProcessor
8
+
9
+ __all__ = [
10
+ "TaskContext",
11
+ "DSLStep",
12
+ "DSLProcessor",
13
+ ]