ambivo-agents 1.0.1__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.
- ambivo_agents/__init__.py +91 -0
- ambivo_agents/agents/__init__.py +21 -0
- ambivo_agents/agents/assistant.py +203 -0
- ambivo_agents/agents/code_executor.py +133 -0
- ambivo_agents/agents/code_executor2.py +222 -0
- ambivo_agents/agents/knowledge_base.py +935 -0
- ambivo_agents/agents/media_editor.py +992 -0
- ambivo_agents/agents/moderator.py +617 -0
- ambivo_agents/agents/simple_web_search.py +404 -0
- ambivo_agents/agents/web_scraper.py +1027 -0
- ambivo_agents/agents/web_search.py +933 -0
- ambivo_agents/agents/youtube_download.py +784 -0
- ambivo_agents/cli.py +699 -0
- ambivo_agents/config/__init__.py +4 -0
- ambivo_agents/config/loader.py +301 -0
- ambivo_agents/core/__init__.py +33 -0
- ambivo_agents/core/base.py +1024 -0
- ambivo_agents/core/history.py +606 -0
- ambivo_agents/core/llm.py +333 -0
- ambivo_agents/core/memory.py +640 -0
- ambivo_agents/executors/__init__.py +8 -0
- ambivo_agents/executors/docker_executor.py +108 -0
- ambivo_agents/executors/media_executor.py +237 -0
- ambivo_agents/executors/youtube_executor.py +404 -0
- ambivo_agents/services/__init__.py +6 -0
- ambivo_agents/services/agent_service.py +605 -0
- ambivo_agents/services/factory.py +370 -0
- ambivo_agents-1.0.1.dist-info/METADATA +1090 -0
- ambivo_agents-1.0.1.dist-info/RECORD +33 -0
- ambivo_agents-1.0.1.dist-info/WHEEL +5 -0
- ambivo_agents-1.0.1.dist-info/entry_points.txt +3 -0
- ambivo_agents-1.0.1.dist-info/licenses/LICENSE +21 -0
- ambivo_agents-1.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,605 @@
|
|
1
|
+
# ambivo_agents/services/agent_service.py
|
2
|
+
"""
|
3
|
+
Agent Service for managing agent sessions and message processing - UPDATED WITH YOUTUBE SUPPORT.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import asyncio
|
7
|
+
import uuid
|
8
|
+
import time
|
9
|
+
import logging
|
10
|
+
from typing import Dict, List, Any, Optional
|
11
|
+
from datetime import datetime, timedelta
|
12
|
+
|
13
|
+
from ..core.base import AgentRole, AgentMessage, MessageType, ExecutionContext
|
14
|
+
from ..core.memory import create_redis_memory_manager
|
15
|
+
from ..core.llm import create_multi_provider_llm_service
|
16
|
+
from ..config.loader import (
|
17
|
+
load_config,
|
18
|
+
get_config_section,
|
19
|
+
validate_agent_capabilities,
|
20
|
+
get_available_agent_types,
|
21
|
+
get_enabled_capabilities,
|
22
|
+
get_available_agent_type_names
|
23
|
+
)
|
24
|
+
from .factory import AgentFactory
|
25
|
+
|
26
|
+
|
27
|
+
class AgentSession:
|
28
|
+
"""Manages a single agent session - UPDATED WITH YOUTUBE SUPPORT"""
|
29
|
+
|
30
|
+
def __init__(self, session_id: str, preferred_llm_provider: str = None):
|
31
|
+
# Load configuration from YAML
|
32
|
+
self.config = load_config()
|
33
|
+
self.session_id = session_id
|
34
|
+
self.redis_config = get_config_section('redis', self.config)
|
35
|
+
self.llm_config = get_config_section('llm', self.config)
|
36
|
+
self.service_config = self.config.get('service', {})
|
37
|
+
|
38
|
+
# Use centralized capability checking
|
39
|
+
self.capabilities = validate_agent_capabilities(self.config)
|
40
|
+
self.available_agent_types = get_available_agent_types(self.config)
|
41
|
+
|
42
|
+
self.preferred_llm_provider = preferred_llm_provider or self.llm_config.get('preferred_provider', 'openai')
|
43
|
+
self.agents = {}
|
44
|
+
self.proxy_agent = None
|
45
|
+
self.created_at = datetime.now()
|
46
|
+
self.last_activity = datetime.now()
|
47
|
+
self.message_count = 0
|
48
|
+
|
49
|
+
# Setup logging
|
50
|
+
log_level = self.service_config.get('log_level', 'INFO')
|
51
|
+
self.logger = logging.getLogger(f"AgentSession-{session_id[:8]}")
|
52
|
+
self.logger.setLevel(getattr(logging, log_level))
|
53
|
+
|
54
|
+
# Initialize LLM service
|
55
|
+
self._initialize_llm_service()
|
56
|
+
|
57
|
+
# Initialize agents for this session
|
58
|
+
self._initialize_agents()
|
59
|
+
|
60
|
+
def _initialize_llm_service(self):
|
61
|
+
"""Initialize the LLM service"""
|
62
|
+
try:
|
63
|
+
self.llm_service = create_multi_provider_llm_service(
|
64
|
+
config_data=self.llm_config,
|
65
|
+
preferred_provider=self.preferred_llm_provider
|
66
|
+
)
|
67
|
+
self.logger.info(f"LLM service initialized with provider: {self.llm_service.get_current_provider()}")
|
68
|
+
except Exception as e:
|
69
|
+
self.logger.error(f"Failed to initialize LLM service: {e}")
|
70
|
+
raise e
|
71
|
+
|
72
|
+
def _initialize_agents(self):
|
73
|
+
"""Initialize all agents based on configuration - UPDATED WITH YOUTUBE SUPPORT"""
|
74
|
+
|
75
|
+
# Core Assistant Agent
|
76
|
+
assistant_id = f"assistant_{self.session_id}"
|
77
|
+
assistant_memory = create_redis_memory_manager(assistant_id, self.redis_config)
|
78
|
+
|
79
|
+
self.agents['assistant'] = AgentFactory.create_agent(
|
80
|
+
role=AgentRole.ASSISTANT,
|
81
|
+
agent_id=assistant_id,
|
82
|
+
memory_manager=assistant_memory,
|
83
|
+
llm_service=self.llm_service,
|
84
|
+
config=self.config
|
85
|
+
)
|
86
|
+
|
87
|
+
# Code Executor Agent (if enabled)
|
88
|
+
if self.capabilities.get('code_execution', False):
|
89
|
+
executor_id = f"executor_{self.session_id}"
|
90
|
+
executor_memory = create_redis_memory_manager(executor_id, self.redis_config)
|
91
|
+
|
92
|
+
self.agents['executor'] = AgentFactory.create_agent(
|
93
|
+
role=AgentRole.CODE_EXECUTOR,
|
94
|
+
agent_id=executor_id,
|
95
|
+
memory_manager=executor_memory,
|
96
|
+
llm_service=self.llm_service,
|
97
|
+
config=self.config
|
98
|
+
)
|
99
|
+
|
100
|
+
# Create specialized agents based on enabled capabilities
|
101
|
+
|
102
|
+
# Web Search Agent (if enabled)
|
103
|
+
if self.capabilities.get('web_search', False):
|
104
|
+
search_id = f"websearch_{self.session_id}"
|
105
|
+
search_memory = create_redis_memory_manager(search_id, self.redis_config)
|
106
|
+
|
107
|
+
try:
|
108
|
+
from ..agents.web_search import WebSearchAgent
|
109
|
+
self.agents['web_search'] = WebSearchAgent(
|
110
|
+
agent_id=search_id,
|
111
|
+
memory_manager=search_memory,
|
112
|
+
llm_service=self.llm_service
|
113
|
+
)
|
114
|
+
self.logger.info("Created WebSearchAgent")
|
115
|
+
except Exception as e:
|
116
|
+
self.logger.error(f"Failed to create WebSearchAgent: {e}")
|
117
|
+
|
118
|
+
# Knowledge Base Agent (if enabled)
|
119
|
+
if self.capabilities.get('knowledge_base', False):
|
120
|
+
kb_id = f"knowledge_{self.session_id}"
|
121
|
+
kb_memory = create_redis_memory_manager(kb_id, self.redis_config)
|
122
|
+
|
123
|
+
try:
|
124
|
+
from ..agents.knowledge_base import KnowledgeBaseAgent
|
125
|
+
self.agents['knowledge_base'] = KnowledgeBaseAgent(
|
126
|
+
agent_id=kb_id,
|
127
|
+
memory_manager=kb_memory,
|
128
|
+
llm_service=self.llm_service
|
129
|
+
)
|
130
|
+
self.logger.info("Created KnowledgeBaseAgent")
|
131
|
+
except Exception as e:
|
132
|
+
self.logger.error(f"Failed to create KnowledgeBaseAgent: {e}")
|
133
|
+
|
134
|
+
# Web Scraper Agent (if enabled)
|
135
|
+
if self.capabilities.get('web_scraping', False):
|
136
|
+
scraper_id = f"webscraper_{self.session_id}"
|
137
|
+
scraper_memory = create_redis_memory_manager(scraper_id, self.redis_config)
|
138
|
+
|
139
|
+
try:
|
140
|
+
from ..agents.web_scraper import WebScraperAgent
|
141
|
+
self.agents['web_scraper'] = WebScraperAgent(
|
142
|
+
agent_id=scraper_id,
|
143
|
+
memory_manager=scraper_memory,
|
144
|
+
llm_service=self.llm_service
|
145
|
+
)
|
146
|
+
self.logger.info("Created WebScraperAgent")
|
147
|
+
except Exception as e:
|
148
|
+
self.logger.error(f"Failed to create WebScraperAgent: {e}")
|
149
|
+
|
150
|
+
# Media Editor Agent (if enabled)
|
151
|
+
if self.capabilities.get('media_editor', False):
|
152
|
+
media_id = f"mediaeditor_{self.session_id}"
|
153
|
+
media_memory = create_redis_memory_manager(media_id, self.redis_config)
|
154
|
+
|
155
|
+
try:
|
156
|
+
from ..agents.media_editor import MediaEditorAgent
|
157
|
+
self.agents['media_editor'] = MediaEditorAgent(
|
158
|
+
agent_id=media_id,
|
159
|
+
memory_manager=media_memory,
|
160
|
+
llm_service=self.llm_service
|
161
|
+
)
|
162
|
+
self.logger.info("Created MediaEditorAgent")
|
163
|
+
except Exception as e:
|
164
|
+
self.logger.error(f"Failed to create MediaEditorAgent: {e}")
|
165
|
+
|
166
|
+
# YouTube Download Agent (if enabled)
|
167
|
+
if self.capabilities.get('youtube_download', False):
|
168
|
+
youtube_id = f"youtube_{self.session_id}"
|
169
|
+
youtube_memory = create_redis_memory_manager(youtube_id, self.redis_config)
|
170
|
+
|
171
|
+
try:
|
172
|
+
from ..agents.youtube_download import YouTubeDownloadAgent
|
173
|
+
self.agents['youtube_download'] = YouTubeDownloadAgent(
|
174
|
+
agent_id=youtube_id,
|
175
|
+
memory_manager=youtube_memory,
|
176
|
+
llm_service=self.llm_service
|
177
|
+
)
|
178
|
+
self.logger.info("Created YouTubeDownloadAgent")
|
179
|
+
except Exception as e:
|
180
|
+
self.logger.error(f"Failed to create YouTubeDownloadAgent: {e}")
|
181
|
+
|
182
|
+
if self.capabilities.get('moderator', False):
|
183
|
+
moderator_id = f"moderator_{self.session_id}"
|
184
|
+
moderator_memory = create_redis_memory_manager(moderator_id, self.redis_config)
|
185
|
+
|
186
|
+
try:
|
187
|
+
from ..agents.moderator import ModeratorAgent
|
188
|
+
self.agents['moderator'] = ModeratorAgent(
|
189
|
+
agent_id=moderator_id,
|
190
|
+
memory_manager=moderator_memory,
|
191
|
+
llm_service=self.llm_service
|
192
|
+
)
|
193
|
+
self.logger.info("Created ModeratorAgent")
|
194
|
+
except Exception as e:
|
195
|
+
self.logger.error(f"Failed to create ModeratorAgent: {e}")
|
196
|
+
|
197
|
+
# Fallback: Create a general researcher agent if no specialized agents were created
|
198
|
+
specialized_agents = ['web_search', 'knowledge_base', 'web_scraper', 'media_editor', 'youtube_download']
|
199
|
+
if not any(key in self.agents for key in specialized_agents):
|
200
|
+
researcher_id = f"researcher_{self.session_id}"
|
201
|
+
researcher_memory = create_redis_memory_manager(researcher_id, self.redis_config)
|
202
|
+
|
203
|
+
self.agents['researcher'] = AgentFactory.create_agent(
|
204
|
+
role=AgentRole.RESEARCHER,
|
205
|
+
agent_id=researcher_id,
|
206
|
+
memory_manager=researcher_memory,
|
207
|
+
llm_service=self.llm_service,
|
208
|
+
config=self.config
|
209
|
+
)
|
210
|
+
self.logger.info("Created fallback researcher agent")
|
211
|
+
|
212
|
+
# Proxy Agent (if enabled)
|
213
|
+
if self.capabilities.get('proxy', True):
|
214
|
+
proxy_id = f"proxy_{self.session_id}"
|
215
|
+
proxy_memory = create_redis_memory_manager(proxy_id, self.redis_config)
|
216
|
+
|
217
|
+
self.proxy_agent = AgentFactory.create_agent(
|
218
|
+
role=AgentRole.PROXY,
|
219
|
+
agent_id=proxy_id,
|
220
|
+
memory_manager=proxy_memory,
|
221
|
+
llm_service=self.llm_service,
|
222
|
+
config=self.config
|
223
|
+
)
|
224
|
+
|
225
|
+
# Register all agents with proxy
|
226
|
+
for agent in self.agents.values():
|
227
|
+
self.proxy_agent.register_agent(agent)
|
228
|
+
|
229
|
+
self.agents['proxy'] = self.proxy_agent
|
230
|
+
|
231
|
+
enabled_capabilities = get_enabled_capabilities(self.config)
|
232
|
+
self.logger.info(f"Initialized session with capabilities: {enabled_capabilities}")
|
233
|
+
|
234
|
+
async def process_message(self,
|
235
|
+
message_content: str,
|
236
|
+
user_id: str,
|
237
|
+
tenant_id: str = "",
|
238
|
+
conversation_id: str = None,
|
239
|
+
metadata: Dict[str, Any] = None) -> AgentMessage:
|
240
|
+
"""Process a user message through the agent system"""
|
241
|
+
|
242
|
+
self.last_activity = datetime.now()
|
243
|
+
self.message_count += 1
|
244
|
+
|
245
|
+
if not conversation_id:
|
246
|
+
conversation_id = str(uuid.uuid4())
|
247
|
+
|
248
|
+
# Create user message
|
249
|
+
user_message = AgentMessage(
|
250
|
+
id=str(uuid.uuid4()),
|
251
|
+
sender_id=f"user_{user_id}",
|
252
|
+
recipient_id=self.proxy_agent.agent_id if self.proxy_agent else list(self.agents.values())[0].agent_id,
|
253
|
+
content=message_content,
|
254
|
+
message_type=MessageType.USER_INPUT,
|
255
|
+
session_id=self.session_id,
|
256
|
+
conversation_id=conversation_id,
|
257
|
+
metadata=metadata or {}
|
258
|
+
)
|
259
|
+
|
260
|
+
# Create execution context
|
261
|
+
context = ExecutionContext(
|
262
|
+
session_id=self.session_id,
|
263
|
+
conversation_id=conversation_id,
|
264
|
+
user_id=user_id,
|
265
|
+
tenant_id=tenant_id,
|
266
|
+
metadata={
|
267
|
+
'message_count': self.message_count,
|
268
|
+
'session_age': (datetime.now() - self.created_at).total_seconds(),
|
269
|
+
'enabled_capabilities': get_enabled_capabilities(self.config),
|
270
|
+
'available_agent_types': get_available_agent_type_names(self.config),
|
271
|
+
'config_source': 'agent_config.yaml',
|
272
|
+
**(metadata or {})
|
273
|
+
}
|
274
|
+
)
|
275
|
+
|
276
|
+
try:
|
277
|
+
# Process through proxy agent if available, otherwise use assistant
|
278
|
+
target_agent = self.proxy_agent or self.agents.get('assistant')
|
279
|
+
|
280
|
+
if not target_agent:
|
281
|
+
raise RuntimeError("No available agents to process message")
|
282
|
+
|
283
|
+
response = await target_agent.process_message(user_message, context)
|
284
|
+
|
285
|
+
# Add session metadata
|
286
|
+
response.metadata.update({
|
287
|
+
'session_id': self.session_id,
|
288
|
+
'message_count': self.message_count,
|
289
|
+
'processing_time': (datetime.now() - self.last_activity).total_seconds(),
|
290
|
+
'enabled_capabilities': get_enabled_capabilities(self.config),
|
291
|
+
'available_agent_types': get_available_agent_type_names(self.config),
|
292
|
+
'config_source': 'agent_config.yaml'
|
293
|
+
})
|
294
|
+
|
295
|
+
self.logger.debug(f"Processed message {self.message_count} in conversation {conversation_id}")
|
296
|
+
return response
|
297
|
+
|
298
|
+
except Exception as e:
|
299
|
+
self.logger.error(f"Error processing message: {e}")
|
300
|
+
error_response = AgentMessage(
|
301
|
+
id=str(uuid.uuid4()),
|
302
|
+
sender_id=target_agent.agent_id if 'target_agent' in locals() else "system",
|
303
|
+
recipient_id=user_message.sender_id,
|
304
|
+
content=f"I encountered an error processing your request: {str(e)}",
|
305
|
+
message_type=MessageType.ERROR,
|
306
|
+
session_id=self.session_id,
|
307
|
+
conversation_id=conversation_id,
|
308
|
+
metadata={'error': str(e), 'message_count': self.message_count, 'config_source': 'agent_config.yaml'}
|
309
|
+
)
|
310
|
+
return error_response
|
311
|
+
|
312
|
+
def get_session_stats(self) -> Dict[str, Any]:
|
313
|
+
"""Get session statistics"""
|
314
|
+
return {
|
315
|
+
'session_id': self.session_id,
|
316
|
+
'created_at': self.created_at.isoformat(),
|
317
|
+
'last_activity': self.last_activity.isoformat(),
|
318
|
+
'message_count': self.message_count,
|
319
|
+
'session_age_seconds': (datetime.now() - self.created_at).total_seconds(),
|
320
|
+
'agent_count': len(self.agents),
|
321
|
+
'available_agents': list(self.agents.keys()),
|
322
|
+
'enabled_capabilities': get_enabled_capabilities(self.config),
|
323
|
+
'available_agent_types': get_available_agent_type_names(self.config),
|
324
|
+
'llm_provider': self.llm_service.get_current_provider() if self.llm_service else None,
|
325
|
+
'config_source': 'agent_config.yaml',
|
326
|
+
'redis_config': {
|
327
|
+
'host': self.redis_config.get('host'),
|
328
|
+
'port': self.redis_config.get('port'),
|
329
|
+
'db': self.redis_config.get('db')
|
330
|
+
}
|
331
|
+
}
|
332
|
+
|
333
|
+
|
334
|
+
class AgentService:
|
335
|
+
"""Agent Service for managing multiple agent sessions - UPDATED WITH YOUTUBE SUPPORT"""
|
336
|
+
|
337
|
+
def __init__(self, preferred_llm_provider: str = None):
|
338
|
+
"""Initialize the Agent Service"""
|
339
|
+
|
340
|
+
# Load configuration from YAML
|
341
|
+
self.config = load_config()
|
342
|
+
self.redis_config = get_config_section('redis', self.config)
|
343
|
+
self.llm_config = get_config_section('llm', self.config)
|
344
|
+
self.service_config = self.config.get('service', {})
|
345
|
+
|
346
|
+
# Use centralized capability checking
|
347
|
+
self.capabilities = validate_agent_capabilities(self.config)
|
348
|
+
self.available_agent_types = get_available_agent_types(self.config)
|
349
|
+
|
350
|
+
self.preferred_llm_provider = preferred_llm_provider or self.llm_config.get('preferred_provider', 'openai')
|
351
|
+
self.sessions: Dict[str, AgentSession] = {}
|
352
|
+
self.session_timeout = self.service_config.get('session_timeout', 3600)
|
353
|
+
self.max_sessions = self.service_config.get('max_sessions', 100)
|
354
|
+
|
355
|
+
# Setup logging
|
356
|
+
self.logger = logging.getLogger("AgentService")
|
357
|
+
self._setup_logging()
|
358
|
+
|
359
|
+
# Performance tracking
|
360
|
+
self.total_messages_processed = 0
|
361
|
+
self.total_sessions_created = 0
|
362
|
+
self.start_time = datetime.now()
|
363
|
+
|
364
|
+
self.logger.info("Agent Service initialized from agent_config.yaml with YouTube support")
|
365
|
+
|
366
|
+
def _setup_logging(self):
|
367
|
+
"""Setup logging configuration"""
|
368
|
+
log_level = self.service_config.get('log_level', 'INFO')
|
369
|
+
log_to_file = self.service_config.get('log_to_file', False)
|
370
|
+
|
371
|
+
handlers = [logging.StreamHandler()]
|
372
|
+
if log_to_file:
|
373
|
+
handlers.append(logging.FileHandler('agent_service.log'))
|
374
|
+
|
375
|
+
logging.basicConfig(
|
376
|
+
level=getattr(logging, log_level),
|
377
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
378
|
+
handlers=handlers
|
379
|
+
)
|
380
|
+
|
381
|
+
def create_session(self, session_id: str = None, preferred_llm_provider: str = None) -> str:
|
382
|
+
"""Create a new agent session"""
|
383
|
+
if not session_id:
|
384
|
+
session_id = str(uuid.uuid4())
|
385
|
+
|
386
|
+
if session_id in self.sessions:
|
387
|
+
self.logger.warning(f"Session {session_id} already exists")
|
388
|
+
return session_id
|
389
|
+
|
390
|
+
# Check session limit
|
391
|
+
if len(self.sessions) >= self.max_sessions:
|
392
|
+
self.cleanup_expired_sessions()
|
393
|
+
if len(self.sessions) >= self.max_sessions:
|
394
|
+
oldest_session = min(self.sessions.values(), key=lambda s: s.last_activity)
|
395
|
+
self.delete_session(oldest_session.session_id)
|
396
|
+
|
397
|
+
try:
|
398
|
+
session = AgentSession(
|
399
|
+
session_id=session_id,
|
400
|
+
preferred_llm_provider=preferred_llm_provider or self.preferred_llm_provider
|
401
|
+
)
|
402
|
+
|
403
|
+
self.sessions[session_id] = session
|
404
|
+
self.total_sessions_created += 1
|
405
|
+
|
406
|
+
self.logger.info(f"Created session {session_id} (total: {len(self.sessions)})")
|
407
|
+
return session_id
|
408
|
+
|
409
|
+
except Exception as e:
|
410
|
+
self.logger.error(f"Failed to create session {session_id}: {e}")
|
411
|
+
raise
|
412
|
+
|
413
|
+
async def process_message(self,
|
414
|
+
message: str,
|
415
|
+
session_id: str,
|
416
|
+
user_id: str,
|
417
|
+
tenant_id: str = "",
|
418
|
+
conversation_id: str = None,
|
419
|
+
metadata: Dict[str, Any] = None) -> Dict[str, Any]:
|
420
|
+
"""Process a user message through the agent system"""
|
421
|
+
|
422
|
+
start_time = time.time()
|
423
|
+
|
424
|
+
try:
|
425
|
+
# Get or create session
|
426
|
+
if session_id not in self.sessions:
|
427
|
+
self.create_session(session_id)
|
428
|
+
|
429
|
+
session = self.sessions[session_id]
|
430
|
+
|
431
|
+
# Process message
|
432
|
+
response = await session.process_message(
|
433
|
+
message_content=message,
|
434
|
+
user_id=user_id,
|
435
|
+
tenant_id=tenant_id,
|
436
|
+
conversation_id=conversation_id,
|
437
|
+
metadata=metadata
|
438
|
+
)
|
439
|
+
|
440
|
+
self.total_messages_processed += 1
|
441
|
+
processing_time = time.time() - start_time
|
442
|
+
|
443
|
+
return {
|
444
|
+
'success': True,
|
445
|
+
'response': response.content,
|
446
|
+
'agent_id': response.sender_id,
|
447
|
+
'message_id': response.id,
|
448
|
+
'conversation_id': response.conversation_id,
|
449
|
+
'session_id': session_id,
|
450
|
+
'metadata': response.metadata,
|
451
|
+
'timestamp': response.timestamp.isoformat(),
|
452
|
+
'processing_time': processing_time,
|
453
|
+
'message_count': session.message_count,
|
454
|
+
'enabled_capabilities': get_enabled_capabilities(self.config),
|
455
|
+
'available_agent_types': get_available_agent_type_names(self.config),
|
456
|
+
'config_source': 'agent_config.yaml'
|
457
|
+
}
|
458
|
+
|
459
|
+
except Exception as e:
|
460
|
+
processing_time = time.time() - start_time
|
461
|
+
self.logger.error(f"Error processing message: {e}")
|
462
|
+
|
463
|
+
return {
|
464
|
+
'success': False,
|
465
|
+
'error': str(e),
|
466
|
+
'session_id': session_id,
|
467
|
+
'timestamp': datetime.now().isoformat(),
|
468
|
+
'processing_time': processing_time,
|
469
|
+
'config_source': 'agent_config.yaml'
|
470
|
+
}
|
471
|
+
|
472
|
+
def get_service_stats(self) -> Dict[str, Any]:
|
473
|
+
"""Get comprehensive service statistics"""
|
474
|
+
current_time = datetime.now()
|
475
|
+
uptime = current_time - self.start_time
|
476
|
+
|
477
|
+
return {
|
478
|
+
'service_status': 'healthy',
|
479
|
+
'uptime_seconds': uptime.total_seconds(),
|
480
|
+
'active_sessions': len(self.sessions),
|
481
|
+
'total_sessions_created': self.total_sessions_created,
|
482
|
+
'total_messages_processed': self.total_messages_processed,
|
483
|
+
'enabled_capabilities': get_enabled_capabilities(self.config),
|
484
|
+
'available_agent_types': self.available_agent_types,
|
485
|
+
'available_agent_type_names': get_available_agent_type_names(self.config),
|
486
|
+
'config_source': 'agent_config.yaml',
|
487
|
+
'configuration_summary': {
|
488
|
+
'redis_host': self.redis_config.get('host'),
|
489
|
+
'redis_port': self.redis_config.get('port'),
|
490
|
+
'llm_provider': self.preferred_llm_provider,
|
491
|
+
'max_sessions': self.max_sessions,
|
492
|
+
'session_timeout': self.session_timeout,
|
493
|
+
'log_level': self.service_config.get('log_level', 'INFO')
|
494
|
+
},
|
495
|
+
'timestamp': current_time.isoformat()
|
496
|
+
}
|
497
|
+
|
498
|
+
def health_check(self) -> dict[str, Any]:
|
499
|
+
"""Comprehensive health check - UPDATED WITH YOUTUBE SUPPORT"""
|
500
|
+
health_status: dict[str, Any] = {
|
501
|
+
'service_available': True,
|
502
|
+
'timestamp': datetime.now().isoformat(),
|
503
|
+
'config_source': 'agent_config.yaml'
|
504
|
+
}
|
505
|
+
|
506
|
+
try:
|
507
|
+
# Test Redis connectivity
|
508
|
+
test_memory = create_redis_memory_manager("health_check", self.redis_config)
|
509
|
+
health_status['redis_available'] = True
|
510
|
+
|
511
|
+
# Test LLM service
|
512
|
+
try:
|
513
|
+
test_llm = create_multi_provider_llm_service(self.llm_config, self.preferred_llm_provider)
|
514
|
+
health_status['llm_service_available'] = True
|
515
|
+
health_status['llm_current_provider'] = test_llm.get_current_provider()
|
516
|
+
health_status['llm_available_providers'] = test_llm.get_available_providers()
|
517
|
+
except Exception as e:
|
518
|
+
health_status['llm_service_available'] = False
|
519
|
+
health_status['llm_error'] = str(e)
|
520
|
+
|
521
|
+
# Agent capabilities using centralized checking
|
522
|
+
health_status['enabled_capabilities'] = get_enabled_capabilities(self.config)
|
523
|
+
health_status['available_agent_types'] = self.available_agent_types
|
524
|
+
health_status['available_agent_type_names'] = get_available_agent_type_names(self.config)
|
525
|
+
|
526
|
+
# Session health
|
527
|
+
health_status.update({
|
528
|
+
'active_sessions': len(self.sessions),
|
529
|
+
'max_sessions': self.max_sessions,
|
530
|
+
'session_capacity_used': len(self.sessions) / self.max_sessions if self.max_sessions > 0 else 0
|
531
|
+
})
|
532
|
+
|
533
|
+
except Exception as e:
|
534
|
+
health_status.update({
|
535
|
+
'service_available': False,
|
536
|
+
'error': str(e),
|
537
|
+
'overall_health': 'unhealthy'
|
538
|
+
})
|
539
|
+
|
540
|
+
return health_status
|
541
|
+
|
542
|
+
def cleanup_expired_sessions(self):
|
543
|
+
"""Remove expired sessions"""
|
544
|
+
current_time = time.time()
|
545
|
+
expired_sessions = []
|
546
|
+
|
547
|
+
for session_id, session in self.sessions.items():
|
548
|
+
session_age = current_time - session.created_at.timestamp()
|
549
|
+
last_activity_age = current_time - session.last_activity.timestamp()
|
550
|
+
|
551
|
+
if (session_age > self.session_timeout or
|
552
|
+
last_activity_age > self.session_timeout):
|
553
|
+
expired_sessions.append(session_id)
|
554
|
+
|
555
|
+
for session_id in expired_sessions:
|
556
|
+
self.delete_session(session_id)
|
557
|
+
|
558
|
+
if expired_sessions:
|
559
|
+
self.logger.info(f"Cleaned up {len(expired_sessions)} expired sessions")
|
560
|
+
|
561
|
+
def delete_session(self, session_id: str) -> bool:
|
562
|
+
"""Delete a session"""
|
563
|
+
if session_id in self.sessions:
|
564
|
+
try:
|
565
|
+
del self.sessions[session_id]
|
566
|
+
self.logger.info(f"Deleted session {session_id}")
|
567
|
+
return True
|
568
|
+
except Exception as e:
|
569
|
+
self.logger.error(f"Error deleting session {session_id}: {e}")
|
570
|
+
return False
|
571
|
+
return False
|
572
|
+
|
573
|
+
def get_session_info(self, session_id: str) -> Optional[Dict[str, Any]]:
|
574
|
+
"""Get detailed information about a session"""
|
575
|
+
session = self.sessions.get(session_id)
|
576
|
+
if session:
|
577
|
+
return session.get_session_stats()
|
578
|
+
return None
|
579
|
+
|
580
|
+
|
581
|
+
def create_agent_service(preferred_llm_provider: str = None) -> AgentService:
|
582
|
+
"""Create agent service using YAML configuration exclusively - UPDATED WITH YOUTUBE SUPPORT"""
|
583
|
+
return AgentService(preferred_llm_provider=preferred_llm_provider)
|
584
|
+
|
585
|
+
|
586
|
+
async def quick_chat(agent_service: AgentService,
|
587
|
+
message: str,
|
588
|
+
user_id: str,
|
589
|
+
session_id: str = None,
|
590
|
+
**kwargs) -> str:
|
591
|
+
"""Quick chat interface"""
|
592
|
+
if not session_id:
|
593
|
+
session_id = str(uuid.uuid4())
|
594
|
+
|
595
|
+
result = await agent_service.process_message(
|
596
|
+
message=message,
|
597
|
+
session_id=session_id,
|
598
|
+
user_id=user_id,
|
599
|
+
**kwargs
|
600
|
+
)
|
601
|
+
|
602
|
+
if result['success']:
|
603
|
+
return result['response']
|
604
|
+
else:
|
605
|
+
return f"Error: {result['error']}"
|