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,370 @@
|
|
1
|
+
# ambivo_agents/services/factory.py
|
2
|
+
"""
|
3
|
+
Agent Factory for creating different types of agents - UPDATED WITH YOUTUBE SUPPORT
|
4
|
+
|
5
|
+
Author: Hemant Gosain 'Sunny'
|
6
|
+
Company: Ambivo
|
7
|
+
Email: sgosain@ambivo.com
|
8
|
+
License: MIT
|
9
|
+
"""
|
10
|
+
|
11
|
+
import logging
|
12
|
+
from typing import Dict, Any, Optional
|
13
|
+
|
14
|
+
from ..core.base import AgentRole, BaseAgent, AgentMessage, MessageType
|
15
|
+
from ..core.memory import MemoryManagerInterface
|
16
|
+
from ..core.llm import LLMServiceInterface
|
17
|
+
from ..config.loader import (
|
18
|
+
load_config,
|
19
|
+
get_config_section,
|
20
|
+
validate_agent_capabilities,
|
21
|
+
get_available_agent_types,
|
22
|
+
get_enabled_capabilities
|
23
|
+
)
|
24
|
+
|
25
|
+
from ..agents.assistant import AssistantAgent
|
26
|
+
from ..agents.code_executor import CodeExecutorAgent
|
27
|
+
|
28
|
+
|
29
|
+
class ProxyAgent(BaseAgent):
|
30
|
+
"""Agent that routes messages to appropriate specialized agents - UPDATED WITH YOUTUBE SUPPORT"""
|
31
|
+
|
32
|
+
def __init__(self, agent_id: str, memory_manager, llm_service=None, **kwargs):
|
33
|
+
super().__init__(
|
34
|
+
agent_id=agent_id,
|
35
|
+
role=AgentRole.PROXY,
|
36
|
+
memory_manager=memory_manager,
|
37
|
+
llm_service=llm_service,
|
38
|
+
name="Proxy Agent",
|
39
|
+
description="Agent that routes messages to appropriate specialized agents",
|
40
|
+
**kwargs
|
41
|
+
)
|
42
|
+
self.agent_registry: Dict[str, BaseAgent] = {}
|
43
|
+
|
44
|
+
def register_agent(self, agent: BaseAgent) -> bool:
|
45
|
+
"""Register an agent for routing"""
|
46
|
+
if agent and hasattr(agent, 'agent_id'):
|
47
|
+
self.agent_registry[agent.agent_id] = agent
|
48
|
+
logging.info(f"Registered agent {agent.agent_id} ({agent.__class__.__name__}) with proxy")
|
49
|
+
return True
|
50
|
+
else:
|
51
|
+
logging.error(f"Failed to register agent: invalid agent object")
|
52
|
+
return False
|
53
|
+
|
54
|
+
def get_registered_agents(self) -> Dict[str, BaseAgent]:
|
55
|
+
"""Get all registered agents"""
|
56
|
+
return self.agent_registry.copy()
|
57
|
+
|
58
|
+
def unregister_agent(self, agent_id: str) -> bool:
|
59
|
+
"""Unregister an agent"""
|
60
|
+
if agent_id in self.agent_registry:
|
61
|
+
del self.agent_registry[agent_id]
|
62
|
+
logging.info(f"Unregistered agent {agent_id} from proxy")
|
63
|
+
return True
|
64
|
+
return False
|
65
|
+
|
66
|
+
async def process_message(self, message, context=None):
|
67
|
+
"""Route messages to appropriate agents based on content analysis - UPDATED WITH YOUTUBE"""
|
68
|
+
self.memory.store_message(message)
|
69
|
+
|
70
|
+
try:
|
71
|
+
content = message.content.lower()
|
72
|
+
|
73
|
+
# Improved routing logic with YouTube support
|
74
|
+
target_agent = None
|
75
|
+
|
76
|
+
# YouTube download routing (HIGHEST PRIORITY for YouTube URLs)
|
77
|
+
if any(keyword in content for keyword in [
|
78
|
+
'youtube.com', 'youtu.be', 'download youtube', 'youtube download',
|
79
|
+
'download video', 'download audio', 'youtube mp3', 'youtube mp4',
|
80
|
+
'download from youtube'
|
81
|
+
]) or 'youtube' in content:
|
82
|
+
# Look for YouTubeDownloadAgent by class name or agent key
|
83
|
+
for agent_key, agent in self.agent_registry.items():
|
84
|
+
if ('YouTubeDownloadAgent' in agent.__class__.__name__ or
|
85
|
+
'youtube_download' in agent_key or
|
86
|
+
'youtube' in agent_key):
|
87
|
+
target_agent = agent
|
88
|
+
break
|
89
|
+
|
90
|
+
# Web search routing (HIGH PRIORITY for web search requests)
|
91
|
+
elif any(keyword in content for keyword in [
|
92
|
+
'search web', 'web search', 'find online', 'search_web',
|
93
|
+
'brave search', 'aves search', 'search the web', 'search for'
|
94
|
+
]):
|
95
|
+
# Look for WebSearchAgent by class name or agent key
|
96
|
+
for agent_key, agent in self.agent_registry.items():
|
97
|
+
if ('WebSearchAgent' in agent.__class__.__name__ or
|
98
|
+
'web_search' in agent_key or
|
99
|
+
'websearch' in agent_key):
|
100
|
+
target_agent = agent
|
101
|
+
break
|
102
|
+
|
103
|
+
# Knowledge Base routing (for KB operations)
|
104
|
+
elif any(keyword in content for keyword in [
|
105
|
+
'ingest_document', 'ingest_text', 'ingest', 'knowledge base', 'kb',
|
106
|
+
'query_knowledge_base', 'query', 'search documents', 'vector database',
|
107
|
+
'qdrant', 'semantic search', 'document', 'pdf', 'docx'
|
108
|
+
]):
|
109
|
+
# Look for KnowledgeBaseAgent
|
110
|
+
for agent_key, agent in self.agent_registry.items():
|
111
|
+
if ('KnowledgeBaseAgent' in agent.__class__.__name__ or
|
112
|
+
'knowledge_base' in agent_key or
|
113
|
+
'knowledge' in agent_key):
|
114
|
+
target_agent = agent
|
115
|
+
break
|
116
|
+
|
117
|
+
# Media processing routing (for FFmpeg operations)
|
118
|
+
elif any(keyword in content for keyword in [
|
119
|
+
'extract_audio', 'convert_video', 'media', 'ffmpeg', 'audio', 'video',
|
120
|
+
'mp4', 'mp3', 'wav', 'extract audio', 'resize video', 'trim video',
|
121
|
+
'video format', 'audio format'
|
122
|
+
]):
|
123
|
+
# Look for MediaEditorAgent
|
124
|
+
for agent_key, agent in self.agent_registry.items():
|
125
|
+
if ('MediaEditorAgent' in agent.__class__.__name__ or
|
126
|
+
'media_editor' in agent_key or
|
127
|
+
'mediaeditor' in agent_key):
|
128
|
+
target_agent = agent
|
129
|
+
break
|
130
|
+
|
131
|
+
# Code execution routing
|
132
|
+
elif any(keyword in content for keyword in [
|
133
|
+
'execute', 'run code', 'python', 'bash', '```python', '```bash',
|
134
|
+
'script', 'code execution'
|
135
|
+
]):
|
136
|
+
# Look for CodeExecutorAgent
|
137
|
+
for agent in self.agent_registry.values():
|
138
|
+
if agent.role == AgentRole.CODE_EXECUTOR:
|
139
|
+
target_agent = agent
|
140
|
+
break
|
141
|
+
|
142
|
+
# Web scraping routing (only for explicit scraping requests)
|
143
|
+
elif any(keyword in content for keyword in [
|
144
|
+
'scrape', 'web scraping', 'crawl', 'extract from url', 'scrape_url',
|
145
|
+
'apartments.com', 'scrape website'
|
146
|
+
]):
|
147
|
+
# Look for WebScraperAgent
|
148
|
+
for agent_key, agent in self.agent_registry.items():
|
149
|
+
if ('WebScraperAgent' in agent.__class__.__name__ or
|
150
|
+
'web_scraper' in agent_key or
|
151
|
+
'webscraper' in agent_key):
|
152
|
+
target_agent = agent
|
153
|
+
break
|
154
|
+
|
155
|
+
# Default to Assistant Agent if no specific routing found
|
156
|
+
if not target_agent:
|
157
|
+
for agent in self.agent_registry.values():
|
158
|
+
if agent.role == AgentRole.ASSISTANT:
|
159
|
+
target_agent = agent
|
160
|
+
break
|
161
|
+
|
162
|
+
if target_agent:
|
163
|
+
logging.info(f"Routing message to {target_agent.__class__.__name__} ({target_agent.agent_id})")
|
164
|
+
logging.info(f"Routing reason: Content analysis for '{content[:50]}...'")
|
165
|
+
|
166
|
+
response = await target_agent.process_message(message, context)
|
167
|
+
|
168
|
+
response.metadata.update({
|
169
|
+
'routed_by': self.agent_id,
|
170
|
+
'routed_to': target_agent.agent_id,
|
171
|
+
'routed_to_class': target_agent.__class__.__name__,
|
172
|
+
'routing_reason': f"Content matched {target_agent.__class__.__name__} patterns"
|
173
|
+
})
|
174
|
+
|
175
|
+
return response
|
176
|
+
else:
|
177
|
+
available_agents = [f"{agent.__class__.__name__} ({agent_id})" for agent_id, agent in
|
178
|
+
self.agent_registry.items()]
|
179
|
+
error_response = self.create_response(
|
180
|
+
content=f"I couldn't find an appropriate agent to handle your request. Available agents: {available_agents}",
|
181
|
+
recipient_id=message.sender_id,
|
182
|
+
message_type=MessageType.ERROR,
|
183
|
+
session_id=message.session_id,
|
184
|
+
conversation_id=message.conversation_id
|
185
|
+
)
|
186
|
+
return error_response
|
187
|
+
|
188
|
+
except Exception as e:
|
189
|
+
logging.error(f"Proxy routing error: {e}")
|
190
|
+
error_response = self.create_response(
|
191
|
+
content=f"Routing error: {str(e)}",
|
192
|
+
recipient_id=message.sender_id,
|
193
|
+
message_type=MessageType.ERROR,
|
194
|
+
session_id=message.session_id,
|
195
|
+
conversation_id=message.conversation_id
|
196
|
+
)
|
197
|
+
return error_response
|
198
|
+
|
199
|
+
|
200
|
+
class AgentFactory:
|
201
|
+
"""Factory for creating different types of agents - UPDATED WITH YOUTUBE SUPPORT"""
|
202
|
+
|
203
|
+
@staticmethod
|
204
|
+
def create_agent(role: AgentRole,
|
205
|
+
agent_id: str,
|
206
|
+
memory_manager: MemoryManagerInterface,
|
207
|
+
llm_service: LLMServiceInterface = None,
|
208
|
+
config: Dict[str, Any] = None,
|
209
|
+
**kwargs) -> BaseAgent:
|
210
|
+
"""Create an agent of the specified role"""
|
211
|
+
|
212
|
+
if role == AgentRole.ASSISTANT:
|
213
|
+
return AssistantAgent(
|
214
|
+
agent_id=agent_id,
|
215
|
+
memory_manager=memory_manager,
|
216
|
+
llm_service=llm_service,
|
217
|
+
**kwargs
|
218
|
+
)
|
219
|
+
elif role == AgentRole.CODE_EXECUTOR:
|
220
|
+
return CodeExecutorAgent(
|
221
|
+
agent_id=agent_id,
|
222
|
+
memory_manager=memory_manager,
|
223
|
+
llm_service=llm_service,
|
224
|
+
**kwargs
|
225
|
+
)
|
226
|
+
elif role == AgentRole.RESEARCHER:
|
227
|
+
# Import specialized agents dynamically based on configuration
|
228
|
+
capabilities = validate_agent_capabilities(config)
|
229
|
+
|
230
|
+
# PRIORITY ORDER: Knowledge Base > Web Search > YouTube > Web Scraper > Media Editor
|
231
|
+
if capabilities.get('knowledge_base', False):
|
232
|
+
try:
|
233
|
+
from ..agents.knowledge_base import KnowledgeBaseAgent
|
234
|
+
logging.info("Creating KnowledgeBaseAgent for RESEARCHER role")
|
235
|
+
return KnowledgeBaseAgent(
|
236
|
+
agent_id=agent_id,
|
237
|
+
memory_manager=memory_manager,
|
238
|
+
llm_service=llm_service,
|
239
|
+
**kwargs
|
240
|
+
)
|
241
|
+
except Exception as e:
|
242
|
+
logging.error(f"Failed to create KnowledgeBaseAgent: {e}")
|
243
|
+
|
244
|
+
elif capabilities.get('web_search', False):
|
245
|
+
try:
|
246
|
+
from ..agents.web_search import WebSearchAgent
|
247
|
+
logging.info("Creating WebSearchAgent for RESEARCHER role")
|
248
|
+
return WebSearchAgent(
|
249
|
+
agent_id=agent_id,
|
250
|
+
memory_manager=memory_manager,
|
251
|
+
llm_service=llm_service,
|
252
|
+
**kwargs
|
253
|
+
)
|
254
|
+
except Exception as e:
|
255
|
+
logging.error(f"Failed to create WebSearchAgent: {e}")
|
256
|
+
|
257
|
+
elif capabilities.get('youtube_download', False):
|
258
|
+
try:
|
259
|
+
from ..agents.youtube_download import YouTubeDownloadAgent
|
260
|
+
logging.info("Creating YouTubeDownloadAgent for RESEARCHER role")
|
261
|
+
return YouTubeDownloadAgent(
|
262
|
+
agent_id=agent_id,
|
263
|
+
memory_manager=memory_manager,
|
264
|
+
llm_service=llm_service,
|
265
|
+
**kwargs
|
266
|
+
)
|
267
|
+
except Exception as e:
|
268
|
+
logging.error(f"Failed to create YouTubeDownloadAgent: {e}")
|
269
|
+
|
270
|
+
elif capabilities.get('web_scraping', False):
|
271
|
+
try:
|
272
|
+
from ..agents.web_scraper import WebScraperAgent
|
273
|
+
logging.info("Creating WebScraperAgent for RESEARCHER role")
|
274
|
+
return WebScraperAgent(
|
275
|
+
agent_id=agent_id,
|
276
|
+
memory_manager=memory_manager,
|
277
|
+
llm_service=llm_service,
|
278
|
+
**kwargs
|
279
|
+
)
|
280
|
+
except Exception as e:
|
281
|
+
logging.error(f"Failed to create WebScraperAgent: {e}")
|
282
|
+
|
283
|
+
elif capabilities.get('media_editor', False):
|
284
|
+
try:
|
285
|
+
from ..agents.media_editor import MediaEditorAgent
|
286
|
+
logging.info("Creating MediaEditorAgent for RESEARCHER role")
|
287
|
+
return MediaEditorAgent(
|
288
|
+
agent_id=agent_id,
|
289
|
+
memory_manager=memory_manager,
|
290
|
+
llm_service=llm_service,
|
291
|
+
**kwargs
|
292
|
+
)
|
293
|
+
except Exception as e:
|
294
|
+
logging.error(f"Failed to create MediaEditorAgent: {e}")
|
295
|
+
|
296
|
+
# Fallback to assistant if no specialized researcher is available
|
297
|
+
logging.warning("No specialized researcher agents available, falling back to AssistantAgent")
|
298
|
+
return AssistantAgent(
|
299
|
+
agent_id=agent_id,
|
300
|
+
memory_manager=memory_manager,
|
301
|
+
llm_service=llm_service,
|
302
|
+
**kwargs
|
303
|
+
)
|
304
|
+
|
305
|
+
elif role == AgentRole.PROXY:
|
306
|
+
return ProxyAgent(
|
307
|
+
agent_id=agent_id,
|
308
|
+
memory_manager=memory_manager,
|
309
|
+
llm_service=llm_service,
|
310
|
+
**kwargs
|
311
|
+
)
|
312
|
+
else:
|
313
|
+
raise ValueError(f"Unsupported agent role: {role}")
|
314
|
+
|
315
|
+
@staticmethod
|
316
|
+
def create_specialized_agent(agent_type: str,
|
317
|
+
agent_id: str,
|
318
|
+
memory_manager: MemoryManagerInterface,
|
319
|
+
llm_service: LLMServiceInterface = None,
|
320
|
+
config: Dict[str, Any] = None,
|
321
|
+
**kwargs) -> BaseAgent:
|
322
|
+
"""Create specialized agents by type name - UPDATED WITH YOUTUBE SUPPORT"""
|
323
|
+
|
324
|
+
capabilities = validate_agent_capabilities(config)
|
325
|
+
|
326
|
+
if agent_type == "knowledge_base":
|
327
|
+
if not capabilities.get('knowledge_base', False):
|
328
|
+
raise ValueError("Knowledge base not enabled in agent_config.yaml")
|
329
|
+
from ..agents.knowledge_base import KnowledgeBaseAgent
|
330
|
+
return KnowledgeBaseAgent(agent_id, memory_manager, llm_service, **kwargs)
|
331
|
+
|
332
|
+
elif agent_type == "web_scraper":
|
333
|
+
if not capabilities.get('web_scraping', False):
|
334
|
+
raise ValueError("Web scraping not enabled in agent_config.yaml")
|
335
|
+
from ..agents.web_scraper import WebScraperAgent
|
336
|
+
return WebScraperAgent(agent_id, memory_manager, llm_service, **kwargs)
|
337
|
+
|
338
|
+
elif agent_type == "web_search":
|
339
|
+
if not capabilities.get('web_search', False):
|
340
|
+
raise ValueError("Web search not enabled in agent_config.yaml")
|
341
|
+
from ..agents.web_search import WebSearchAgent
|
342
|
+
return WebSearchAgent(agent_id, memory_manager, llm_service, **kwargs)
|
343
|
+
|
344
|
+
elif agent_type == "media_editor":
|
345
|
+
if not capabilities.get('media_editor', False):
|
346
|
+
raise ValueError("Media editor not enabled in agent_config.yaml")
|
347
|
+
from ..agents.media_editor import MediaEditorAgent
|
348
|
+
return MediaEditorAgent(agent_id, memory_manager, llm_service, **kwargs)
|
349
|
+
|
350
|
+
elif agent_type == "youtube_download":
|
351
|
+
if not capabilities.get('youtube_download', False):
|
352
|
+
raise ValueError("YouTube download not enabled in agent_config.yaml")
|
353
|
+
from ..agents.youtube_download import YouTubeDownloadAgent
|
354
|
+
return YouTubeDownloadAgent(agent_id, memory_manager, llm_service, **kwargs)
|
355
|
+
elif agent_type == "moderator":
|
356
|
+
|
357
|
+
from ..agents.moderator import ModeratorAgent
|
358
|
+
return ModeratorAgent(agent_id, memory_manager, llm_service, **kwargs)
|
359
|
+
|
360
|
+
else:
|
361
|
+
raise ValueError(f"Unknown or unavailable agent type: {agent_type}")
|
362
|
+
|
363
|
+
@staticmethod
|
364
|
+
def get_available_agent_types(config: Dict[str, Any] = None) -> Dict[str, bool]:
|
365
|
+
"""
|
366
|
+
Get available agent types based on configuration.
|
367
|
+
|
368
|
+
This now uses the centralized capability checking from loader.py
|
369
|
+
"""
|
370
|
+
return get_available_agent_types(config)
|