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,301 @@
|
|
1
|
+
# ambivo_agents/config/loader.py
|
2
|
+
"""
|
3
|
+
Configuration loader for ambivo_agents.
|
4
|
+
All configurations must be sourced from agent_config.yaml - no defaults.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import os
|
8
|
+
import yaml
|
9
|
+
from pathlib import Path
|
10
|
+
from typing import Dict, Any
|
11
|
+
|
12
|
+
|
13
|
+
class ConfigurationError(Exception):
|
14
|
+
"""Raised when configuration is missing or invalid."""
|
15
|
+
pass
|
16
|
+
|
17
|
+
|
18
|
+
def load_config(config_path: str = None) -> Dict[str, Any]:
|
19
|
+
"""
|
20
|
+
Load configuration from agent_config.yaml.
|
21
|
+
|
22
|
+
Args:
|
23
|
+
config_path: Optional path to config file. If None, searches for agent_config.yaml
|
24
|
+
in current directory and parent directories.
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
Configuration dictionary
|
28
|
+
|
29
|
+
Raises:
|
30
|
+
ConfigurationError: If config file is not found or invalid
|
31
|
+
"""
|
32
|
+
if config_path:
|
33
|
+
config_file = Path(config_path)
|
34
|
+
else:
|
35
|
+
# Search for agent_config.yaml starting from current directory
|
36
|
+
config_file = _find_config_file()
|
37
|
+
|
38
|
+
if not config_file or not config_file.exists():
|
39
|
+
raise ConfigurationError(
|
40
|
+
"agent_config.yaml not found. This file is required for ambivo_agents to function. "
|
41
|
+
"Please create agent_config.yaml in your project root or specify the path explicitly."
|
42
|
+
)
|
43
|
+
|
44
|
+
try:
|
45
|
+
with open(config_file, 'r', encoding='utf-8') as f:
|
46
|
+
config = yaml.safe_load(f)
|
47
|
+
|
48
|
+
if not config:
|
49
|
+
raise ConfigurationError("agent_config.yaml is empty or contains invalid YAML")
|
50
|
+
|
51
|
+
# Validate required sections
|
52
|
+
_validate_config(config)
|
53
|
+
|
54
|
+
return config
|
55
|
+
|
56
|
+
except yaml.YAMLError as e:
|
57
|
+
raise ConfigurationError(f"Invalid YAML in agent_config.yaml: {e}")
|
58
|
+
except Exception as e:
|
59
|
+
raise ConfigurationError(f"Failed to load agent_config.yaml: {e}")
|
60
|
+
|
61
|
+
|
62
|
+
def _find_config_file() -> Path:
|
63
|
+
"""Find agent_config.yaml in current directory or parent directories."""
|
64
|
+
current_dir = Path.cwd()
|
65
|
+
|
66
|
+
# Check current directory first
|
67
|
+
config_file = current_dir / "agent_config.yaml"
|
68
|
+
if config_file.exists():
|
69
|
+
return config_file
|
70
|
+
|
71
|
+
# Check parent directories
|
72
|
+
for parent in current_dir.parents:
|
73
|
+
config_file = parent / "agent_config.yaml"
|
74
|
+
if config_file.exists():
|
75
|
+
return config_file
|
76
|
+
|
77
|
+
return None
|
78
|
+
|
79
|
+
|
80
|
+
def _validate_config(config: Dict[str, Any]) -> None:
|
81
|
+
"""
|
82
|
+
Validate that required configuration sections exist.
|
83
|
+
|
84
|
+
Args:
|
85
|
+
config: Configuration dictionary
|
86
|
+
|
87
|
+
Raises:
|
88
|
+
ConfigurationError: If required sections are missing
|
89
|
+
"""
|
90
|
+
required_sections = ['redis', 'llm']
|
91
|
+
missing_sections = []
|
92
|
+
|
93
|
+
for section in required_sections:
|
94
|
+
if section not in config:
|
95
|
+
missing_sections.append(section)
|
96
|
+
|
97
|
+
if missing_sections:
|
98
|
+
raise ConfigurationError(
|
99
|
+
f"Required configuration sections missing: {missing_sections}. "
|
100
|
+
"Please check your agent_config.yaml file."
|
101
|
+
)
|
102
|
+
|
103
|
+
# Validate Redis config
|
104
|
+
redis_config = config['redis']
|
105
|
+
required_redis_fields = ['host', 'port']
|
106
|
+
missing_redis_fields = [field for field in required_redis_fields if field not in redis_config]
|
107
|
+
|
108
|
+
if missing_redis_fields:
|
109
|
+
raise ConfigurationError(
|
110
|
+
f"Required Redis configuration fields missing: {missing_redis_fields}"
|
111
|
+
)
|
112
|
+
|
113
|
+
# Validate LLM config
|
114
|
+
llm_config = config['llm']
|
115
|
+
has_api_key = any(key in llm_config for key in [
|
116
|
+
'openai_api_key', 'anthropic_api_key', 'aws_access_key_id'
|
117
|
+
])
|
118
|
+
|
119
|
+
if not has_api_key:
|
120
|
+
raise ConfigurationError(
|
121
|
+
"At least one LLM provider API key is required in llm configuration. "
|
122
|
+
"Supported providers: openai_api_key, anthropic_api_key, aws_access_key_id"
|
123
|
+
)
|
124
|
+
|
125
|
+
|
126
|
+
def get_config_section(section: str, config: Dict[str, Any] = None) -> Dict[str, Any]:
|
127
|
+
"""
|
128
|
+
Get a specific configuration section.
|
129
|
+
|
130
|
+
Args:
|
131
|
+
section: Section name (e.g., 'redis', 'llm', 'web_scraping')
|
132
|
+
config: Optional config dict. If None, loads from file.
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
Configuration section dictionary
|
136
|
+
|
137
|
+
Raises:
|
138
|
+
ConfigurationError: If section is not found
|
139
|
+
"""
|
140
|
+
if config is None:
|
141
|
+
config = load_config()
|
142
|
+
|
143
|
+
if section not in config:
|
144
|
+
raise ConfigurationError(f"Configuration section '{section}' not found in agent_config.yaml")
|
145
|
+
|
146
|
+
return config[section]
|
147
|
+
|
148
|
+
|
149
|
+
# Centralized capability and agent type mapping - UPDATED WITH YOUTUBE
|
150
|
+
CAPABILITY_TO_AGENT_TYPE = {
|
151
|
+
'assistant': 'assistant',
|
152
|
+
'code_execution': 'code_executor',
|
153
|
+
'proxy': 'proxy',
|
154
|
+
'web_scraping': 'web_scraper',
|
155
|
+
'knowledge_base': 'knowledge_base',
|
156
|
+
'web_search': 'web_search',
|
157
|
+
'media_editor': 'media_editor',
|
158
|
+
'youtube_download': 'youtube_download' # NEW
|
159
|
+
}
|
160
|
+
|
161
|
+
CONFIG_FLAG_TO_CAPABILITY = {
|
162
|
+
'enable_web_scraping': 'web_scraping',
|
163
|
+
'enable_knowledge_base': 'knowledge_base',
|
164
|
+
'enable_web_search': 'web_search',
|
165
|
+
'enable_media_editor': 'media_editor',
|
166
|
+
'enable_youtube_download': 'youtube_download', # NEW
|
167
|
+
'enable_code_execution': 'code_execution',
|
168
|
+
'enable_proxy_mode': 'proxy'
|
169
|
+
}
|
170
|
+
|
171
|
+
|
172
|
+
def validate_agent_capabilities(config: Dict[str, Any] = None) -> Dict[str, bool]:
|
173
|
+
"""
|
174
|
+
Validate and return available agent capabilities based on configuration.
|
175
|
+
|
176
|
+
This is the SINGLE SOURCE OF TRUTH for capability checking.
|
177
|
+
|
178
|
+
Args:
|
179
|
+
config: Optional config dict. If None, loads from file.
|
180
|
+
|
181
|
+
Returns:
|
182
|
+
Dictionary of capability_name -> enabled status
|
183
|
+
"""
|
184
|
+
if config is None:
|
185
|
+
config = load_config()
|
186
|
+
|
187
|
+
# Always available capabilities
|
188
|
+
capabilities = {
|
189
|
+
'assistant': True, # Always available
|
190
|
+
'code_execution': True, # Always available with Docker
|
191
|
+
'proxy': True, # Always available
|
192
|
+
}
|
193
|
+
|
194
|
+
# Get agent_capabilities section
|
195
|
+
agent_caps = config.get('agent_capabilities', {})
|
196
|
+
|
197
|
+
# Check optional capabilities based on both flag AND config section existence
|
198
|
+
capabilities['web_scraping'] = (
|
199
|
+
agent_caps.get('enable_web_scraping', False) and
|
200
|
+
'web_scraping' in config
|
201
|
+
)
|
202
|
+
|
203
|
+
capabilities['knowledge_base'] = (
|
204
|
+
agent_caps.get('enable_knowledge_base', False) and
|
205
|
+
'knowledge_base' in config
|
206
|
+
)
|
207
|
+
|
208
|
+
capabilities['web_search'] = (
|
209
|
+
agent_caps.get('enable_web_search', False) and
|
210
|
+
'web_search' in config
|
211
|
+
)
|
212
|
+
|
213
|
+
capabilities['media_editor'] = (
|
214
|
+
agent_caps.get('enable_media_editor', False) and
|
215
|
+
'media_editor' in config
|
216
|
+
)
|
217
|
+
|
218
|
+
# YouTube download capability
|
219
|
+
capabilities['youtube_download'] = (
|
220
|
+
agent_caps.get('enable_youtube_download', False) and
|
221
|
+
'youtube_download' in config
|
222
|
+
)
|
223
|
+
|
224
|
+
return capabilities
|
225
|
+
|
226
|
+
|
227
|
+
def get_available_agent_types(config: Dict[str, Any] = None) -> Dict[str, bool]:
|
228
|
+
"""
|
229
|
+
Get available agent types based on capabilities.
|
230
|
+
|
231
|
+
This maps capabilities to agent type names consistently.
|
232
|
+
|
233
|
+
Args:
|
234
|
+
config: Optional config dict. If None, loads from file.
|
235
|
+
|
236
|
+
Returns:
|
237
|
+
Dictionary of agent_type_name -> available status
|
238
|
+
"""
|
239
|
+
try:
|
240
|
+
capabilities = validate_agent_capabilities(config)
|
241
|
+
|
242
|
+
# Map capabilities to agent types using centralized mapping
|
243
|
+
agent_types = {}
|
244
|
+
for capability, agent_type in CAPABILITY_TO_AGENT_TYPE.items():
|
245
|
+
agent_types[agent_type] = capabilities.get(capability, False)
|
246
|
+
|
247
|
+
return agent_types
|
248
|
+
|
249
|
+
except Exception as e:
|
250
|
+
import logging
|
251
|
+
logging.error(f"Error getting available agent types: {e}")
|
252
|
+
# Safe fallback
|
253
|
+
return {
|
254
|
+
'assistant': True,
|
255
|
+
'code_executor': True,
|
256
|
+
'proxy': True,
|
257
|
+
'knowledge_base': False,
|
258
|
+
'web_scraper': False,
|
259
|
+
'web_search': False,
|
260
|
+
'media_editor': False,
|
261
|
+
'youtube_download': False
|
262
|
+
}
|
263
|
+
|
264
|
+
|
265
|
+
def get_enabled_capabilities(config: Dict[str, Any] = None) -> list[str]:
|
266
|
+
"""
|
267
|
+
Get list of enabled capability names.
|
268
|
+
|
269
|
+
Args:
|
270
|
+
config: Optional config dict. If None, loads from file.
|
271
|
+
|
272
|
+
Returns:
|
273
|
+
List of enabled capability names
|
274
|
+
"""
|
275
|
+
capabilities = validate_agent_capabilities(config)
|
276
|
+
return [cap for cap, enabled in capabilities.items() if enabled]
|
277
|
+
|
278
|
+
|
279
|
+
def get_available_agent_type_names(config: Dict[str, Any] = None) -> list[str]:
|
280
|
+
"""
|
281
|
+
Get list of available agent type names.
|
282
|
+
|
283
|
+
Args:
|
284
|
+
config: Optional config dict. If None, loads from file.
|
285
|
+
|
286
|
+
Returns:
|
287
|
+
List of available agent type names
|
288
|
+
"""
|
289
|
+
agent_types = get_available_agent_types(config)
|
290
|
+
return [agent_type for agent_type, available in agent_types.items() if available]
|
291
|
+
|
292
|
+
|
293
|
+
def capability_to_agent_type(capability: str) -> str:
|
294
|
+
"""Convert capability name to agent type name."""
|
295
|
+
return CAPABILITY_TO_AGENT_TYPE.get(capability, capability)
|
296
|
+
|
297
|
+
|
298
|
+
def agent_type_to_capability(agent_type: str) -> str:
|
299
|
+
"""Convert agent type name to capability name."""
|
300
|
+
reverse_mapping = {v: k for k, v in CAPABILITY_TO_AGENT_TYPE.items()}
|
301
|
+
return reverse_mapping.get(agent_type, agent_type)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# ambivo_agents/core/__init__.py
|
2
|
+
from .base import (
|
3
|
+
AgentRole,
|
4
|
+
MessageType,
|
5
|
+
AgentMessage,
|
6
|
+
AgentTool,
|
7
|
+
ExecutionContext,
|
8
|
+
BaseAgent,
|
9
|
+
ProviderConfig,
|
10
|
+
ProviderTracker,
|
11
|
+
AgentSession
|
12
|
+
)
|
13
|
+
from .memory import MemoryManagerInterface, RedisMemoryManager, create_redis_memory_manager
|
14
|
+
from .llm import LLMServiceInterface, MultiProviderLLMService, create_multi_provider_llm_service
|
15
|
+
|
16
|
+
__all__ = [
|
17
|
+
"AgentRole",
|
18
|
+
"MessageType",
|
19
|
+
"AgentMessage",
|
20
|
+
"AgentTool",
|
21
|
+
"ExecutionContext",
|
22
|
+
"BaseAgent",
|
23
|
+
"ProviderConfig",
|
24
|
+
"ProviderTracker",
|
25
|
+
"MemoryManagerInterface",
|
26
|
+
"RedisMemoryManager",
|
27
|
+
"create_redis_memory_manager",
|
28
|
+
"LLMServiceInterface",
|
29
|
+
"MultiProviderLLMService",
|
30
|
+
"create_multi_provider_llm_service",
|
31
|
+
"AgentSession"
|
32
|
+
]
|
33
|
+
|