agentcrew-ai 0.8.13__py3-none-any.whl → 0.9.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.
Files changed (55) hide show
  1. AgentCrew/__init__.py +1 -1
  2. AgentCrew/app.py +46 -634
  3. AgentCrew/main_docker.py +1 -30
  4. AgentCrew/modules/a2a/common/client/card_resolver.py +27 -8
  5. AgentCrew/modules/a2a/server.py +5 -0
  6. AgentCrew/modules/a2a/task_manager.py +1 -0
  7. AgentCrew/modules/agents/local_agent.py +2 -2
  8. AgentCrew/modules/chat/message/command_processor.py +33 -8
  9. AgentCrew/modules/chat/message/conversation.py +18 -1
  10. AgentCrew/modules/chat/message/handler.py +5 -1
  11. AgentCrew/modules/code_analysis/service.py +50 -7
  12. AgentCrew/modules/code_analysis/tool.py +9 -8
  13. AgentCrew/modules/console/completers.py +5 -1
  14. AgentCrew/modules/console/console_ui.py +23 -11
  15. AgentCrew/modules/console/conversation_browser/__init__.py +9 -0
  16. AgentCrew/modules/console/conversation_browser/browser.py +84 -0
  17. AgentCrew/modules/console/conversation_browser/browser_input_handler.py +279 -0
  18. AgentCrew/modules/console/{conversation_browser.py → conversation_browser/browser_ui.py} +249 -163
  19. AgentCrew/modules/console/conversation_handler.py +34 -1
  20. AgentCrew/modules/console/display_handlers.py +127 -7
  21. AgentCrew/modules/console/visual_mode/__init__.py +5 -0
  22. AgentCrew/modules/console/visual_mode/viewer.py +41 -0
  23. AgentCrew/modules/console/visual_mode/viewer_input_handler.py +315 -0
  24. AgentCrew/modules/console/visual_mode/viewer_ui.py +608 -0
  25. AgentCrew/modules/gui/components/command_handler.py +137 -29
  26. AgentCrew/modules/gui/components/menu_components.py +8 -7
  27. AgentCrew/modules/gui/themes/README.md +30 -14
  28. AgentCrew/modules/gui/themes/__init__.py +2 -1
  29. AgentCrew/modules/gui/themes/atom_light.yaml +1287 -0
  30. AgentCrew/modules/gui/themes/catppuccin.yaml +1276 -0
  31. AgentCrew/modules/gui/themes/dracula.yaml +1262 -0
  32. AgentCrew/modules/gui/themes/nord.yaml +1267 -0
  33. AgentCrew/modules/gui/themes/saigontech.yaml +1268 -0
  34. AgentCrew/modules/gui/themes/style_provider.py +78 -264
  35. AgentCrew/modules/gui/themes/theme_loader.py +379 -0
  36. AgentCrew/modules/gui/themes/unicorn.yaml +1276 -0
  37. AgentCrew/modules/gui/widgets/configs/global_settings.py +4 -4
  38. AgentCrew/modules/gui/widgets/history_sidebar.py +6 -1
  39. AgentCrew/modules/llm/constants.py +28 -9
  40. AgentCrew/modules/mcpclient/service.py +0 -1
  41. AgentCrew/modules/memory/base_service.py +13 -0
  42. AgentCrew/modules/memory/chroma_service.py +50 -0
  43. AgentCrew/setup.py +470 -0
  44. {agentcrew_ai-0.8.13.dist-info → agentcrew_ai-0.9.1.dist-info}/METADATA +1 -1
  45. {agentcrew_ai-0.8.13.dist-info → agentcrew_ai-0.9.1.dist-info}/RECORD +49 -40
  46. {agentcrew_ai-0.8.13.dist-info → agentcrew_ai-0.9.1.dist-info}/WHEEL +1 -1
  47. AgentCrew/modules/gui/themes/atom_light.py +0 -1365
  48. AgentCrew/modules/gui/themes/catppuccin.py +0 -1404
  49. AgentCrew/modules/gui/themes/dracula.py +0 -1372
  50. AgentCrew/modules/gui/themes/nord.py +0 -1365
  51. AgentCrew/modules/gui/themes/saigontech.py +0 -1359
  52. AgentCrew/modules/gui/themes/unicorn.py +0 -1372
  53. {agentcrew_ai-0.8.13.dist-info → agentcrew_ai-0.9.1.dist-info}/entry_points.txt +0 -0
  54. {agentcrew_ai-0.8.13.dist-info → agentcrew_ai-0.9.1.dist-info}/licenses/LICENSE +0 -0
  55. {agentcrew_ai-0.8.13.dist-info → agentcrew_ai-0.9.1.dist-info}/top_level.txt +0 -0
AgentCrew/setup.py ADDED
@@ -0,0 +1,470 @@
1
+ import os
2
+ import json
3
+ import time
4
+ import webbrowser
5
+ from typing import Optional, Dict, Any
6
+
7
+ import click
8
+ import requests
9
+
10
+ from AgentCrew.modules.config import ConfigManagement
11
+ from AgentCrew.modules.llm.model_registry import ModelRegistry
12
+ from AgentCrew.modules.llm.service_manager import ServiceManager
13
+ from AgentCrew.modules.memory.chroma_service import ChromaMemoryService
14
+ from AgentCrew.modules.memory.context_persistent import ContextPersistenceService
15
+ from AgentCrew.modules.clipboard import ClipboardService
16
+ from AgentCrew.modules.web_search import TavilySearchService
17
+ from AgentCrew.modules.code_analysis import CodeAnalysisService
18
+ from AgentCrew.modules.image_generation import ImageGenerationService
19
+ from AgentCrew.modules.browser_automation import BrowserAutomationService
20
+ from AgentCrew.modules.agents.manager import AgentManager
21
+ from AgentCrew.modules.agents.local_agent import LocalAgent
22
+ from AgentCrew.modules.agents.remote_agent import RemoteAgent
23
+ from AgentCrew.modules.agents.example import (
24
+ DEFAULT_NAME,
25
+ DEFAULT_DESCRIPTION,
26
+ DEFAULT_PROMPT,
27
+ )
28
+
29
+
30
+ PROVIDER_LIST = [
31
+ "claude",
32
+ "groq",
33
+ "openai",
34
+ "google",
35
+ "deepinfra",
36
+ "github_copilot",
37
+ "copilot_response",
38
+ ]
39
+
40
+
41
+ class ApplicationSetup:
42
+ def __init__(self, config_manager: Optional[ConfigManagement] = None):
43
+ self.config_manager = config_manager or ConfigManagement()
44
+ self.services: Optional[Dict[str, Any]] = None
45
+ self.agent_manager: Optional[AgentManager] = None
46
+
47
+ def load_api_keys_from_config(self) -> None:
48
+ config_file_path = os.getenv("AGENTCREW_CONFIG_PATH")
49
+ if not config_file_path:
50
+ config_file_path = "./config.json"
51
+ config_file_path = os.path.expanduser(config_file_path)
52
+
53
+ api_keys_config = {}
54
+ if os.path.exists(config_file_path):
55
+ try:
56
+ with open(config_file_path, "r", encoding="utf-8") as f:
57
+ loaded_config = json.load(f)
58
+ if isinstance(loaded_config, dict) and isinstance(
59
+ loaded_config.get("api_keys"), dict
60
+ ):
61
+ api_keys_config = loaded_config["api_keys"]
62
+ else:
63
+ click.echo(
64
+ f"\u26a0\ufe0f API keys in {config_file_path} are not in the expected format.",
65
+ err=True,
66
+ )
67
+ except json.JSONDecodeError:
68
+ click.echo(
69
+ f"\u26a0\ufe0f Error decoding API keys from {config_file_path}.",
70
+ err=True,
71
+ )
72
+ except Exception as e:
73
+ click.echo(
74
+ f"\u26a0\ufe0f Could not load API keys from {config_file_path}: {e}",
75
+ err=True,
76
+ )
77
+
78
+ keys_to_check = [
79
+ "ANTHROPIC_API_KEY",
80
+ "GEMINI_API_KEY",
81
+ "OPENAI_API_KEY",
82
+ "GROQ_API_KEY",
83
+ "DEEPINFRA_API_KEY",
84
+ "GITHUB_COPILOT_API_KEY",
85
+ "TAVILY_API_KEY",
86
+ "VOYAGE_API_KEY",
87
+ "ELEVENLABS_API_KEY",
88
+ ]
89
+
90
+ for key_name in keys_to_check:
91
+ if key_name in api_keys_config and api_keys_config[key_name]:
92
+ os.environ[key_name] = str(api_keys_config[key_name]).strip()
93
+
94
+ def detect_provider(self) -> Optional[str]:
95
+ try:
96
+ last_provider = self.config_manager.get_last_used_provider()
97
+ if last_provider:
98
+ if last_provider in PROVIDER_LIST:
99
+ api_key_map = {
100
+ "claude": "ANTHROPIC_API_KEY",
101
+ "google": "GEMINI_API_KEY",
102
+ "openai": "OPENAI_API_KEY",
103
+ "groq": "GROQ_API_KEY",
104
+ "deepinfra": "DEEPINFRA_API_KEY",
105
+ "github_copilot": "GITHUB_COPILOT_API_KEY",
106
+ "copilot_response": "GITHUB_COPILOT_API_KEY",
107
+ }
108
+ if os.getenv(api_key_map.get(last_provider, "")):
109
+ return last_provider
110
+ else:
111
+ custom_providers = (
112
+ self.config_manager.read_custom_llm_providers_config()
113
+ )
114
+ if any(p["name"] == last_provider for p in custom_providers):
115
+ return last_provider
116
+ except Exception as e:
117
+ click.echo(f"\u26a0\ufe0f Could not restore last used provider: {e}")
118
+
119
+ if os.getenv("GITHUB_COPILOT_API_KEY"):
120
+ return "github_copilot"
121
+ elif os.getenv("ANTHROPIC_API_KEY"):
122
+ return "claude"
123
+ elif os.getenv("GEMINI_API_KEY"):
124
+ return "google"
125
+ elif os.getenv("OPENAI_API_KEY"):
126
+ return "openai"
127
+ elif os.getenv("GROQ_API_KEY"):
128
+ return "groq"
129
+ elif os.getenv("DEEPINFRA_API_KEY"):
130
+ return "deepinfra"
131
+ else:
132
+ custom_providers = self.config_manager.read_custom_llm_providers_config()
133
+ if len(custom_providers) > 0:
134
+ return custom_providers[0]["name"]
135
+
136
+ return None
137
+
138
+ def setup_services(
139
+ self, provider: str, memory_llm: Optional[str] = None, need_memory: bool = True
140
+ ) -> Dict[str, Any]:
141
+ registry = ModelRegistry.get_instance()
142
+ llm_manager = ServiceManager.get_instance()
143
+
144
+ models = registry.get_models_by_provider(provider)
145
+ if models:
146
+ default_model = next((m for m in models if m.default), models[0])
147
+ registry.set_current_model(f"{default_model.provider}/{default_model.id}")
148
+
149
+ llm_service = llm_manager.get_service(provider)
150
+
151
+ try:
152
+ last_model = self.config_manager.get_last_used_model()
153
+ last_provider = self.config_manager.get_last_used_provider()
154
+
155
+ if last_model and last_provider:
156
+ should_restore = False
157
+ if provider == last_provider:
158
+ should_restore = True
159
+
160
+ last_model_class = registry.get_model(last_model)
161
+ if should_restore and last_model_class:
162
+ llm_service.model = last_model_class.id
163
+ except Exception as e:
164
+ click.echo(f"\u26a0\ufe0f Could not restore last used model: {e}")
165
+
166
+ memory_service = None
167
+ context_service = None
168
+ if need_memory:
169
+ if memory_llm:
170
+ memory_service = ChromaMemoryService(
171
+ llm_service=llm_manager.initialize_standalone_service(memory_llm)
172
+ )
173
+ else:
174
+ memory_service = ChromaMemoryService(
175
+ llm_service=llm_manager.initialize_standalone_service(provider)
176
+ )
177
+
178
+ context_service = ContextPersistenceService()
179
+ clipboard_service = ClipboardService()
180
+
181
+ try:
182
+ search_service = TavilySearchService()
183
+ except Exception as e:
184
+ click.echo(f"\u26a0\ufe0f Web search tools not available: {str(e)}")
185
+ search_service = None
186
+
187
+ try:
188
+ code_analysis_llm = llm_manager.initialize_standalone_service(provider)
189
+ code_analysis_service = CodeAnalysisService(llm_service=code_analysis_llm)
190
+ except Exception as e:
191
+ click.echo(f"\u26a0\ufe0f Code analysis tool not available: {str(e)}")
192
+ code_analysis_service = None
193
+
194
+ try:
195
+ if os.getenv("OPENAI_API_KEY"):
196
+ image_gen_service = ImageGenerationService()
197
+ else:
198
+ image_gen_service = None
199
+ click.echo(
200
+ "\u26a0\ufe0f Image generation service not available: No API keys found."
201
+ )
202
+ except Exception as e:
203
+ click.echo(f"\u26a0\ufe0f Image generation service not available: {str(e)}")
204
+ image_gen_service = None
205
+
206
+ try:
207
+ browser_automation_service = BrowserAutomationService()
208
+ except Exception as e:
209
+ click.echo(
210
+ f"\u26a0\ufe0f Browser automation service not available: {str(e)}"
211
+ )
212
+ browser_automation_service = None
213
+
214
+ try:
215
+ from AgentCrew.modules.file_editing import FileEditingService
216
+
217
+ file_editing_service = FileEditingService()
218
+ except Exception as e:
219
+ click.echo(f"\u26a0\ufe0f File editing service not available: {str(e)}")
220
+ file_editing_service = None
221
+
222
+ try:
223
+ from AgentCrew.modules.command_execution import CommandExecutionService
224
+
225
+ command_execution_service = CommandExecutionService.get_instance()
226
+ except Exception as e:
227
+ click.echo(
228
+ f"\u26a0\ufe0f Command execution service not available: {str(e)}"
229
+ )
230
+ command_execution_service = None
231
+
232
+ self.services = {
233
+ "llm": llm_service,
234
+ "memory": memory_service,
235
+ "clipboard": clipboard_service,
236
+ "code_analysis": code_analysis_service,
237
+ "web_search": search_service,
238
+ "context_persistent": context_service,
239
+ "image_generation": image_gen_service,
240
+ "browser": browser_automation_service,
241
+ "file_editing": file_editing_service,
242
+ "command_execution": command_execution_service,
243
+ }
244
+ return self.services
245
+
246
+ def setup_agents(
247
+ self,
248
+ services: Dict[str, Any],
249
+ config_uri: Optional[str] = None,
250
+ remoting_provider: Optional[str] = None,
251
+ model_id: Optional[str] = None,
252
+ ) -> AgentManager:
253
+ self.agent_manager = AgentManager.get_instance()
254
+ llm_manager = ServiceManager.get_instance()
255
+
256
+ services["agent_manager"] = self.agent_manager
257
+
258
+ global_config = self.config_manager.read_global_config_data()
259
+ self.agent_manager.context_shrink_enabled = global_config.get(
260
+ "global_settings", {}
261
+ ).get("auto_context_shrink", True)
262
+ self.agent_manager.shrink_excluded_list = global_config.get(
263
+ "global_settings", {}
264
+ ).get("shrink_excluded", [])
265
+
266
+ llm_service = services["llm"]
267
+
268
+ if config_uri:
269
+ os.environ["SW_AGENTS_CONFIG"] = config_uri
270
+ else:
271
+ config_uri = os.getenv("SW_AGENTS_CONFIG")
272
+ if not config_uri:
273
+ config_uri = "./agents.toml"
274
+ if not os.path.exists(config_uri):
275
+ click.echo(
276
+ f"Agent configuration not found at {config_uri}. Creating default configuration."
277
+ )
278
+ os.makedirs(os.path.dirname(config_uri), exist_ok=True)
279
+
280
+ default_config = f"""
281
+ [[agents]]
282
+ name = "{DEFAULT_NAME}"
283
+ description = "{DEFAULT_DESCRIPTION}"
284
+ system_prompt = '''{DEFAULT_PROMPT}'''
285
+ tools = ["memory", "browser", "web_search", "code_analysis"]
286
+ """
287
+
288
+ with open(config_uri, "w+", encoding="utf-8") as f:
289
+ f.write(default_config)
290
+
291
+ click.echo(f"Created default agent configuration at {config_uri}")
292
+
293
+ agent_definitions = AgentManager.load_agents_from_config(config_uri)
294
+
295
+ for agent_def in agent_definitions:
296
+ if agent_def.get("base_url", ""):
297
+ try:
298
+ agent = RemoteAgent(
299
+ agent_def["name"],
300
+ agent_def.get("base_url"),
301
+ headers=agent_def.get("headers", {}),
302
+ )
303
+ except Exception:
304
+ print("Error: cannot connect to remote agent, skipping...")
305
+ continue
306
+ else:
307
+ if remoting_provider:
308
+ llm_service = llm_manager.initialize_standalone_service(
309
+ remoting_provider
310
+ )
311
+ if model_id:
312
+ llm_service.model = model_id
313
+ agent = LocalAgent(
314
+ name=agent_def["name"],
315
+ description=agent_def["description"],
316
+ llm_service=llm_service,
317
+ services=services,
318
+ tools=agent_def["tools"],
319
+ temperature=agent_def.get("temperature", None),
320
+ voice_enabled=agent_def.get("voice_enabled", "disabled"),
321
+ voice_id=agent_def.get("voice_id", None),
322
+ )
323
+ agent.set_system_prompt(agent_def["system_prompt"])
324
+ if remoting_provider:
325
+ agent.set_custom_system_prompt(
326
+ self.agent_manager.get_remote_system_prompt()
327
+ )
328
+ agent.is_remoting_mode = True
329
+ agent.activate()
330
+ self.agent_manager.register_agent(agent)
331
+
332
+ from AgentCrew.modules.mcpclient.tool import register as mcp_register
333
+
334
+ mcp_register()
335
+
336
+ if remoting_provider:
337
+ from AgentCrew.modules.mcpclient import MCPSessionManager
338
+
339
+ mcp_manager = MCPSessionManager.get_instance()
340
+ mcp_manager.initialize_for_agent()
341
+ return self.agent_manager
342
+
343
+ return self.agent_manager
344
+
345
+ def restore_last_agent(self) -> None:
346
+ initial_agent_selected = False
347
+ try:
348
+ last_agent = self.config_manager.get_last_used_agent()
349
+
350
+ if (
351
+ last_agent
352
+ and self.agent_manager
353
+ and last_agent in self.agent_manager.agents
354
+ ):
355
+ if self.agent_manager.select_agent(last_agent):
356
+ initial_agent_selected = True
357
+ except Exception as e:
358
+ click.echo(f"\u26a0\ufe0f Could not restore last used agent: {e}")
359
+
360
+ if not initial_agent_selected and self.agent_manager:
361
+ first_agent_name = list(self.agent_manager.agents.keys())[0]
362
+ if not self.agent_manager.select_agent(first_agent_name):
363
+ available_agents = ", ".join(self.agent_manager.agents.keys())
364
+ click.echo(
365
+ f"\u26a0\ufe0f Unknown agent: {first_agent_name}. Using default agent. Available agents: {available_agents}"
366
+ )
367
+
368
+ def login(self) -> bool:
369
+ try:
370
+ click.echo("\U0001f510 Starting GitHub Copilot authentication...")
371
+
372
+ resp = requests.post(
373
+ "https://github.com/login/device/code",
374
+ headers={
375
+ "accept": "application/json",
376
+ "editor-version": "vscode/1.100.3",
377
+ "editor-plugin-version": "GitHub.copilot/1.330.0",
378
+ "content-type": "application/json",
379
+ "user-agent": "GithubCopilot/1.330.0",
380
+ "accept-encoding": "gzip,deflate,br",
381
+ },
382
+ data='{"client_id":"Iv1.b507a08c87ecfe98","scope":"read:user"}',
383
+ )
384
+
385
+ if resp.status_code != 200:
386
+ click.echo(
387
+ f"\u274c Failed to get device code: {resp.status_code}", err=True
388
+ )
389
+ return False
390
+
391
+ resp_json = resp.json()
392
+ device_code = resp_json.get("device_code")
393
+ user_code = resp_json.get("user_code")
394
+ verification_uri = resp_json.get("verification_uri")
395
+
396
+ if not all([device_code, user_code, verification_uri]):
397
+ click.echo("\u274c Invalid response from GitHub", err=True)
398
+ return False
399
+
400
+ click.echo(
401
+ f"\U0001f4cb Please visit {verification_uri} and enter code: {user_code}"
402
+ )
403
+ click.echo("\u23f3 Waiting for authentication...")
404
+
405
+ webbrowser.open(verification_uri)
406
+
407
+ while True:
408
+ time.sleep(5)
409
+
410
+ resp = requests.post(
411
+ "https://github.com/login/oauth/access_token",
412
+ headers={
413
+ "accept": "application/json",
414
+ "editor-version": "vscode/1.100.3",
415
+ "editor-plugin-version": "GitHub.copilot/1.330.0",
416
+ "content-type": "application/json",
417
+ "user-agent": "GithubCopilot/1.330.0",
418
+ "accept-encoding": "gzip,deflate,br",
419
+ },
420
+ data=f'{{"client_id":"Iv1.b507a08c87ecfe98","device_code":"{device_code}","grant_type":"urn:ietf:params:oauth:grant-type:device_code"}}',
421
+ )
422
+
423
+ resp_json = resp.json()
424
+ access_token = resp_json.get("access_token")
425
+ error = resp_json.get("error")
426
+
427
+ if access_token:
428
+ click.echo("\u2705 Authentication successful!")
429
+ break
430
+ elif error == "authorization_pending":
431
+ continue
432
+ elif error == "slow_down":
433
+ time.sleep(5)
434
+ continue
435
+ elif error == "expired_token":
436
+ click.echo(
437
+ "\u274c Authentication expired. Please try again.", err=True
438
+ )
439
+ return False
440
+ elif error == "access_denied":
441
+ click.echo("\u274c Authentication denied by user.", err=True)
442
+ return False
443
+ else:
444
+ click.echo(f"\u274c Authentication error: {error}", err=True)
445
+ return False
446
+
447
+ global_config = self.config_manager.read_global_config_data()
448
+
449
+ if "api_keys" not in global_config:
450
+ global_config["api_keys"] = {}
451
+
452
+ global_config["api_keys"]["GITHUB_COPILOT_API_KEY"] = access_token
453
+ self.config_manager.write_global_config_data(global_config)
454
+
455
+ click.echo("\U0001f4be GitHub Copilot API key saved to config file!")
456
+ click.echo(
457
+ "\U0001f680 You can now use GitHub Copilot with --provider github_copilot"
458
+ )
459
+ return True
460
+
461
+ except ImportError:
462
+ click.echo(
463
+ "\u274c Error: 'requests' package is required for authentication",
464
+ err=True,
465
+ )
466
+ click.echo("Install it with: pip install requests")
467
+ return False
468
+ except Exception as e:
469
+ click.echo(f"\u274c Authentication failed: {str(e)}", err=True)
470
+ return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentcrew-ai
3
- Version: 0.8.13
3
+ Version: 0.9.1
4
4
  Summary: Multi-Agents Interactive Chat Tool
5
5
  Author-email: Quy Truong <quy.truong@saigontechnology.com>
6
6
  License-Expression: Apache-2.0