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.
- AgentCrew/__init__.py +1 -1
- AgentCrew/app.py +46 -634
- AgentCrew/main_docker.py +1 -30
- AgentCrew/modules/a2a/common/client/card_resolver.py +27 -8
- AgentCrew/modules/a2a/server.py +5 -0
- AgentCrew/modules/a2a/task_manager.py +1 -0
- AgentCrew/modules/agents/local_agent.py +2 -2
- AgentCrew/modules/chat/message/command_processor.py +33 -8
- AgentCrew/modules/chat/message/conversation.py +18 -1
- AgentCrew/modules/chat/message/handler.py +5 -1
- AgentCrew/modules/code_analysis/service.py +50 -7
- AgentCrew/modules/code_analysis/tool.py +9 -8
- AgentCrew/modules/console/completers.py +5 -1
- AgentCrew/modules/console/console_ui.py +23 -11
- AgentCrew/modules/console/conversation_browser/__init__.py +9 -0
- AgentCrew/modules/console/conversation_browser/browser.py +84 -0
- AgentCrew/modules/console/conversation_browser/browser_input_handler.py +279 -0
- AgentCrew/modules/console/{conversation_browser.py → conversation_browser/browser_ui.py} +249 -163
- AgentCrew/modules/console/conversation_handler.py +34 -1
- AgentCrew/modules/console/display_handlers.py +127 -7
- AgentCrew/modules/console/visual_mode/__init__.py +5 -0
- AgentCrew/modules/console/visual_mode/viewer.py +41 -0
- AgentCrew/modules/console/visual_mode/viewer_input_handler.py +315 -0
- AgentCrew/modules/console/visual_mode/viewer_ui.py +608 -0
- AgentCrew/modules/gui/components/command_handler.py +137 -29
- AgentCrew/modules/gui/components/menu_components.py +8 -7
- AgentCrew/modules/gui/themes/README.md +30 -14
- AgentCrew/modules/gui/themes/__init__.py +2 -1
- AgentCrew/modules/gui/themes/atom_light.yaml +1287 -0
- AgentCrew/modules/gui/themes/catppuccin.yaml +1276 -0
- AgentCrew/modules/gui/themes/dracula.yaml +1262 -0
- AgentCrew/modules/gui/themes/nord.yaml +1267 -0
- AgentCrew/modules/gui/themes/saigontech.yaml +1268 -0
- AgentCrew/modules/gui/themes/style_provider.py +78 -264
- AgentCrew/modules/gui/themes/theme_loader.py +379 -0
- AgentCrew/modules/gui/themes/unicorn.yaml +1276 -0
- AgentCrew/modules/gui/widgets/configs/global_settings.py +4 -4
- AgentCrew/modules/gui/widgets/history_sidebar.py +6 -1
- AgentCrew/modules/llm/constants.py +28 -9
- AgentCrew/modules/mcpclient/service.py +0 -1
- AgentCrew/modules/memory/base_service.py +13 -0
- AgentCrew/modules/memory/chroma_service.py +50 -0
- AgentCrew/setup.py +470 -0
- {agentcrew_ai-0.8.13.dist-info → agentcrew_ai-0.9.1.dist-info}/METADATA +1 -1
- {agentcrew_ai-0.8.13.dist-info → agentcrew_ai-0.9.1.dist-info}/RECORD +49 -40
- {agentcrew_ai-0.8.13.dist-info → agentcrew_ai-0.9.1.dist-info}/WHEEL +1 -1
- AgentCrew/modules/gui/themes/atom_light.py +0 -1365
- AgentCrew/modules/gui/themes/catppuccin.py +0 -1404
- AgentCrew/modules/gui/themes/dracula.py +0 -1372
- AgentCrew/modules/gui/themes/nord.py +0 -1365
- AgentCrew/modules/gui/themes/saigontech.py +0 -1359
- AgentCrew/modules/gui/themes/unicorn.py +0 -1372
- {agentcrew_ai-0.8.13.dist-info → agentcrew_ai-0.9.1.dist-info}/entry_points.txt +0 -0
- {agentcrew_ai-0.8.13.dist-info → agentcrew_ai-0.9.1.dist-info}/licenses/LICENSE +0 -0
- {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
|