jarvis-ai-assistant 0.1.96__py3-none-any.whl → 0.1.98__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.
Potentially problematic release.
This version of jarvis-ai-assistant might be problematic. Click here for more details.
- jarvis/__init__.py +1 -1
- jarvis/agent.py +138 -144
- jarvis/jarvis_codebase/main.py +87 -54
- jarvis/jarvis_coder/git_utils.py +22 -25
- jarvis/jarvis_coder/main.py +166 -171
- jarvis/jarvis_coder/patch_handler.py +153 -453
- jarvis/jarvis_coder/plan_generator.py +76 -48
- jarvis/jarvis_platform/main.py +39 -39
- jarvis/jarvis_rag/main.py +182 -182
- jarvis/jarvis_smart_shell/main.py +34 -34
- jarvis/main.py +24 -24
- jarvis/models/ai8.py +22 -22
- jarvis/models/base.py +17 -13
- jarvis/models/kimi.py +31 -31
- jarvis/models/ollama.py +28 -28
- jarvis/models/openai.py +22 -24
- jarvis/models/oyi.py +25 -25
- jarvis/models/registry.py +33 -34
- jarvis/tools/ask_user.py +5 -5
- jarvis/tools/base.py +2 -2
- jarvis/tools/chdir.py +9 -9
- jarvis/tools/codebase_qa.py +4 -4
- jarvis/tools/coder.py +4 -4
- jarvis/tools/file_ops.py +1 -1
- jarvis/tools/generator.py +23 -23
- jarvis/tools/methodology.py +4 -4
- jarvis/tools/rag.py +4 -4
- jarvis/tools/registry.py +38 -38
- jarvis/tools/search.py +42 -42
- jarvis/tools/shell.py +13 -13
- jarvis/tools/sub_agent.py +16 -16
- jarvis/tools/thinker.py +41 -41
- jarvis/tools/webpage.py +17 -17
- jarvis/utils.py +59 -60
- {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/METADATA +1 -1
- jarvis_ai_assistant-0.1.98.dist-info/RECORD +47 -0
- jarvis_ai_assistant-0.1.96.dist-info/RECORD +0 -47
- {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/top_level.txt +0 -0
jarvis/models/ollama.py
CHANGED
|
@@ -6,56 +6,56 @@ import os
|
|
|
6
6
|
import json
|
|
7
7
|
|
|
8
8
|
class OllamaPlatform(BasePlatform):
|
|
9
|
-
"""Ollama
|
|
9
|
+
"""Ollama platform implementation"""
|
|
10
10
|
|
|
11
11
|
platform_name = "ollama"
|
|
12
12
|
|
|
13
13
|
def __init__(self):
|
|
14
|
-
"""
|
|
14
|
+
"""Initialize model"""
|
|
15
15
|
super().__init__()
|
|
16
16
|
|
|
17
|
-
#
|
|
17
|
+
# Check environment variables and provide help information
|
|
18
18
|
self.api_base = os.getenv("OLLAMA_API_BASE", "http://localhost:11434")
|
|
19
19
|
self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-r1:1.5b"
|
|
20
20
|
|
|
21
|
-
#
|
|
21
|
+
# Check if Ollama service is available
|
|
22
22
|
try:
|
|
23
23
|
response = requests.get(f"{self.api_base}/api/tags")
|
|
24
24
|
response.raise_for_status()
|
|
25
25
|
available_models = [model["name"] for model in response.json().get("models", [])]
|
|
26
26
|
|
|
27
27
|
if not available_models:
|
|
28
|
-
PrettyOutput.print("\
|
|
29
|
-
PrettyOutput.print("1.
|
|
30
|
-
PrettyOutput.print("2.
|
|
28
|
+
PrettyOutput.print("\nNeed to download Ollama model first to use:", OutputType.INFO)
|
|
29
|
+
PrettyOutput.print("1. Install Ollama: https://ollama.ai", OutputType.INFO)
|
|
30
|
+
PrettyOutput.print("2. Download model:", OutputType.INFO)
|
|
31
31
|
PrettyOutput.print(f" ollama pull {self.model_name}", OutputType.INFO)
|
|
32
|
-
PrettyOutput.print("Ollama
|
|
32
|
+
PrettyOutput.print("Ollama has no available models", OutputType.WARNING)
|
|
33
33
|
|
|
34
34
|
except requests.exceptions.ConnectionError:
|
|
35
|
-
PrettyOutput.print("\nOllama
|
|
36
|
-
PrettyOutput.print("
|
|
37
|
-
PrettyOutput.print("1.
|
|
38
|
-
PrettyOutput.print("2.
|
|
39
|
-
PrettyOutput.print("3.
|
|
35
|
+
PrettyOutput.print("\nOllama service is not started or cannot be connected", OutputType.WARNING)
|
|
36
|
+
PrettyOutput.print("Please ensure that you have:", OutputType.INFO)
|
|
37
|
+
PrettyOutput.print("1. Installed Ollama: https://ollama.ai", OutputType.INFO)
|
|
38
|
+
PrettyOutput.print("2. Started Ollama service", OutputType.INFO)
|
|
39
|
+
PrettyOutput.print("3. Service address configured correctly (default: http://localhost:11434)", OutputType.INFO)
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
self.messages = []
|
|
43
43
|
self.system_message = ""
|
|
44
44
|
|
|
45
45
|
def get_model_list(self) -> List[Tuple[str, str]]:
|
|
46
|
-
"""
|
|
46
|
+
"""Get model list"""
|
|
47
47
|
response = requests.get(f"{self.api_base}/api/tags")
|
|
48
48
|
response.raise_for_status()
|
|
49
49
|
return [(model["name"], "") for model in response.json().get("models", [])]
|
|
50
50
|
|
|
51
51
|
def set_model_name(self, model_name: str):
|
|
52
|
-
"""
|
|
52
|
+
"""Set model name"""
|
|
53
53
|
self.model_name = model_name
|
|
54
54
|
|
|
55
55
|
def chat(self, message: str) -> str:
|
|
56
|
-
"""
|
|
56
|
+
"""Execute conversation"""
|
|
57
57
|
try:
|
|
58
|
-
#
|
|
58
|
+
# Build message list
|
|
59
59
|
messages = []
|
|
60
60
|
if self.system_message:
|
|
61
61
|
messages.append({"role": "system", "content": self.system_message})
|
|
@@ -102,31 +102,31 @@ class OllamaPlatform(BasePlatform):
|
|
|
102
102
|
return full_response
|
|
103
103
|
|
|
104
104
|
except Exception as e:
|
|
105
|
-
PrettyOutput.print(f"
|
|
105
|
+
PrettyOutput.print(f"Chat failed: {str(e)}", OutputType.ERROR)
|
|
106
106
|
raise Exception(f"Chat failed: {str(e)}")
|
|
107
107
|
|
|
108
108
|
def upload_files(self, file_list: List[str]) -> List[Dict]:
|
|
109
|
-
"""
|
|
110
|
-
PrettyOutput.print("Ollama
|
|
109
|
+
"""Upload files (Ollama does not support file upload)"""
|
|
110
|
+
PrettyOutput.print("Ollama does not support file upload", output_type=OutputType.WARNING)
|
|
111
111
|
return []
|
|
112
112
|
|
|
113
113
|
def reset(self):
|
|
114
|
-
"""
|
|
114
|
+
"""Reset model state"""
|
|
115
115
|
self.messages = []
|
|
116
116
|
if self.system_message:
|
|
117
117
|
self.messages.append({"role": "system", "content": self.system_message})
|
|
118
118
|
|
|
119
119
|
def name(self) -> str:
|
|
120
|
-
"""
|
|
120
|
+
"""Return model name"""
|
|
121
121
|
return self.model_name
|
|
122
122
|
|
|
123
123
|
def delete_chat(self) -> bool:
|
|
124
|
-
"""
|
|
124
|
+
"""Delete current chat session"""
|
|
125
125
|
self.reset()
|
|
126
126
|
return True
|
|
127
127
|
|
|
128
128
|
def set_system_message(self, message: str):
|
|
129
|
-
"""
|
|
129
|
+
"""Set system message"""
|
|
130
130
|
self.system_message = message
|
|
131
131
|
self.reset() # 重置会话以应用新的系统消息
|
|
132
132
|
|
|
@@ -136,10 +136,10 @@ if __name__ == "__main__":
|
|
|
136
136
|
ollama = OllamaPlatform()
|
|
137
137
|
while True:
|
|
138
138
|
try:
|
|
139
|
-
message = input("\
|
|
140
|
-
ollama.
|
|
139
|
+
message = input("\nInput question (Ctrl+C to exit): ")
|
|
140
|
+
ollama.chat_until_success(message)
|
|
141
141
|
except KeyboardInterrupt:
|
|
142
|
-
print("\
|
|
142
|
+
print("\nGoodbye!")
|
|
143
143
|
break
|
|
144
144
|
except Exception as e:
|
|
145
|
-
PrettyOutput.print(f"
|
|
145
|
+
PrettyOutput.print(f"Program exited with an exception: {str(e)}", OutputType.ERROR)
|
jarvis/models/openai.py
CHANGED
|
@@ -5,35 +5,33 @@ from jarvis.models.base import BasePlatform
|
|
|
5
5
|
from jarvis.utils import PrettyOutput, OutputType
|
|
6
6
|
|
|
7
7
|
class OpenAIModel(BasePlatform):
|
|
8
|
-
"""DeepSeek模型实现"""
|
|
9
|
-
|
|
10
8
|
platform_name = "openai"
|
|
11
9
|
|
|
12
10
|
def upload_files(self, file_list: List[str]):
|
|
13
|
-
"""
|
|
14
|
-
PrettyOutput.print("OpenAI
|
|
11
|
+
"""Upload files"""
|
|
12
|
+
PrettyOutput.print("OpenAI does not support file upload", OutputType.WARNING)
|
|
15
13
|
|
|
16
14
|
def __init__(self):
|
|
17
15
|
"""
|
|
18
|
-
|
|
16
|
+
Initialize OpenAI model
|
|
19
17
|
"""
|
|
20
18
|
super().__init__()
|
|
21
19
|
self.system_message = ""
|
|
22
20
|
self.api_key = os.getenv("OPENAI_API_KEY")
|
|
23
21
|
if not self.api_key:
|
|
24
|
-
PrettyOutput.print("\
|
|
25
|
-
PrettyOutput.print(" • OPENAI_API_KEY: API
|
|
26
|
-
PrettyOutput.print(" • OPENAI_API_BASE: (
|
|
27
|
-
PrettyOutput.print("\
|
|
28
|
-
PrettyOutput.print("1.
|
|
22
|
+
PrettyOutput.print("\nNeed to set the following environment variables to use OpenAI model:", OutputType.INFO)
|
|
23
|
+
PrettyOutput.print(" • OPENAI_API_KEY: API key", OutputType.INFO)
|
|
24
|
+
PrettyOutput.print(" • OPENAI_API_BASE: (optional) API base address, default using https://api.openai.com/v1", OutputType.INFO)
|
|
25
|
+
PrettyOutput.print("\nYou can set them in the following ways:", OutputType.INFO)
|
|
26
|
+
PrettyOutput.print("1. Create or edit ~/.jarvis_env file:", OutputType.INFO)
|
|
29
27
|
PrettyOutput.print(" OPENAI_API_KEY=your_api_key", OutputType.INFO)
|
|
30
28
|
PrettyOutput.print(" OPENAI_API_BASE=your_api_base", OutputType.INFO)
|
|
31
29
|
PrettyOutput.print(" OPENAI_MODEL_NAME=your_model_name", OutputType.INFO)
|
|
32
|
-
PrettyOutput.print("\n2.
|
|
30
|
+
PrettyOutput.print("\n2. Or set the environment variables directly:", OutputType.INFO)
|
|
33
31
|
PrettyOutput.print(" export OPENAI_API_KEY=your_api_key", OutputType.INFO)
|
|
34
32
|
PrettyOutput.print(" export OPENAI_API_BASE=your_api_base", OutputType.INFO)
|
|
35
33
|
PrettyOutput.print(" export OPENAI_MODEL_NAME=your_model_name", OutputType.INFO)
|
|
36
|
-
PrettyOutput.print("OPENAI_API_KEY
|
|
34
|
+
PrettyOutput.print("OPENAI_API_KEY is not set", OutputType.WARNING)
|
|
37
35
|
|
|
38
36
|
self.base_url = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
|
|
39
37
|
self.model_name = os.getenv("JARVIS_MODEL") or "gpt-4o"
|
|
@@ -47,28 +45,28 @@ class OpenAIModel(BasePlatform):
|
|
|
47
45
|
self.system_message = ""
|
|
48
46
|
|
|
49
47
|
def get_model_list(self) -> List[Tuple[str, str]]:
|
|
50
|
-
"""
|
|
48
|
+
"""Get model list"""
|
|
51
49
|
return []
|
|
52
50
|
|
|
53
51
|
def set_model_name(self, model_name: str):
|
|
54
|
-
"""
|
|
52
|
+
"""Set model name"""
|
|
55
53
|
|
|
56
54
|
self.model_name = model_name
|
|
57
55
|
|
|
58
56
|
def set_system_message(self, message: str):
|
|
59
|
-
"""
|
|
57
|
+
"""Set system message"""
|
|
60
58
|
self.system_message = message
|
|
61
59
|
self.messages.append({"role": "system", "content": self.system_message})
|
|
62
60
|
|
|
63
61
|
def chat(self, message: str) -> str:
|
|
64
|
-
"""
|
|
62
|
+
"""Execute conversation"""
|
|
65
63
|
try:
|
|
66
64
|
|
|
67
|
-
#
|
|
65
|
+
# Add user message to history
|
|
68
66
|
self.messages.append({"role": "user", "content": message})
|
|
69
67
|
|
|
70
68
|
response = self.client.chat.completions.create(
|
|
71
|
-
model=self.model_name, #
|
|
69
|
+
model=self.model_name, # Use the configured model name
|
|
72
70
|
messages=self.messages, # type: ignore
|
|
73
71
|
stream=True
|
|
74
72
|
) # type: ignore
|
|
@@ -85,28 +83,28 @@ class OpenAIModel(BasePlatform):
|
|
|
85
83
|
if not self.suppress_output:
|
|
86
84
|
PrettyOutput.print_stream_end()
|
|
87
85
|
|
|
88
|
-
#
|
|
86
|
+
# Add assistant reply to history
|
|
89
87
|
self.messages.append({"role": "assistant", "content": full_response})
|
|
90
88
|
|
|
91
89
|
return full_response
|
|
92
90
|
|
|
93
91
|
except Exception as e:
|
|
94
|
-
PrettyOutput.print(f"
|
|
92
|
+
PrettyOutput.print(f"Chat failed: {str(e)}", OutputType.ERROR)
|
|
95
93
|
raise Exception(f"Chat failed: {str(e)}")
|
|
96
94
|
|
|
97
95
|
def name(self) -> str:
|
|
98
|
-
"""
|
|
96
|
+
"""Return model name"""
|
|
99
97
|
return self.model_name
|
|
100
98
|
|
|
101
99
|
def reset(self):
|
|
102
|
-
"""
|
|
103
|
-
#
|
|
100
|
+
"""Reset model state"""
|
|
101
|
+
# Clear conversation history, only keep system message
|
|
104
102
|
if self.system_message:
|
|
105
103
|
self.messages = [{"role": "system", "content": self.system_message}]
|
|
106
104
|
else:
|
|
107
105
|
self.messages = []
|
|
108
106
|
|
|
109
107
|
def delete_chat(self)->bool:
|
|
110
|
-
"""
|
|
108
|
+
"""Delete conversation"""
|
|
111
109
|
self.reset()
|
|
112
110
|
return True
|
jarvis/models/oyi.py
CHANGED
|
@@ -13,7 +13,7 @@ class OyiModel(BasePlatform):
|
|
|
13
13
|
BASE_URL = "https://api-10086.rcouyi.com"
|
|
14
14
|
|
|
15
15
|
def get_model_list(self) -> List[Tuple[str, str]]:
|
|
16
|
-
"""
|
|
16
|
+
"""Get model list"""
|
|
17
17
|
return [(name,info['desc']) for name,info in self.models.items()]
|
|
18
18
|
|
|
19
19
|
def __init__(self):
|
|
@@ -28,15 +28,15 @@ class OyiModel(BasePlatform):
|
|
|
28
28
|
|
|
29
29
|
self.token = os.getenv("OYI_API_KEY")
|
|
30
30
|
if not self.token:
|
|
31
|
-
PrettyOutput.print("OYI_API_KEY
|
|
31
|
+
PrettyOutput.print("OYI_API_KEY is not set", OutputType.WARNING)
|
|
32
32
|
|
|
33
33
|
self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
|
|
34
34
|
if self.model_name not in [m.split()[0] for m in self.get_available_models()]:
|
|
35
|
-
PrettyOutput.print(f"
|
|
35
|
+
PrettyOutput.print(f"Warning: The selected model {self.model_name} is not in the available list", OutputType.WARNING)
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
def set_model_name(self, model_name: str):
|
|
39
|
-
"""
|
|
39
|
+
"""Set model name"""
|
|
40
40
|
|
|
41
41
|
self.model_name = model_name
|
|
42
42
|
|
|
@@ -54,7 +54,7 @@ class OyiModel(BasePlatform):
|
|
|
54
54
|
payload = {
|
|
55
55
|
"id": 0,
|
|
56
56
|
"roleId": 0,
|
|
57
|
-
"title": "
|
|
57
|
+
"title": "New conversation",
|
|
58
58
|
"isLock": False,
|
|
59
59
|
"systemMessage": "",
|
|
60
60
|
"params": json.dumps({
|
|
@@ -82,14 +82,14 @@ class OyiModel(BasePlatform):
|
|
|
82
82
|
self.conversation = data
|
|
83
83
|
return True
|
|
84
84
|
else:
|
|
85
|
-
PrettyOutput.print(f"
|
|
85
|
+
PrettyOutput.print(f"Create conversation failed: {data['message']}", OutputType.ERROR)
|
|
86
86
|
return False
|
|
87
87
|
else:
|
|
88
|
-
PrettyOutput.print(f"
|
|
88
|
+
PrettyOutput.print(f"Create conversation failed: {response.status_code}", OutputType.ERROR)
|
|
89
89
|
return False
|
|
90
90
|
|
|
91
91
|
except Exception as e:
|
|
92
|
-
PrettyOutput.print(f"
|
|
92
|
+
PrettyOutput.print(f"Create conversation failed: {str(e)}", OutputType.ERROR)
|
|
93
93
|
return False
|
|
94
94
|
|
|
95
95
|
def set_system_message(self, message: str):
|
|
@@ -155,13 +155,13 @@ class OyiModel(BasePlatform):
|
|
|
155
155
|
)
|
|
156
156
|
|
|
157
157
|
if response.status_code != 200:
|
|
158
|
-
error_msg = f"
|
|
158
|
+
error_msg = f"Chat request failed: {response.status_code}"
|
|
159
159
|
PrettyOutput.print(error_msg, OutputType.ERROR)
|
|
160
160
|
raise Exception(error_msg)
|
|
161
161
|
|
|
162
162
|
data = response.json()
|
|
163
163
|
if data['code'] != 200 or data['type'] != 'success':
|
|
164
|
-
error_msg = f"
|
|
164
|
+
error_msg = f"Chat failed: {data.get('message', 'Unknown error')}"
|
|
165
165
|
PrettyOutput.print(error_msg, OutputType.ERROR)
|
|
166
166
|
raise Exception(error_msg)
|
|
167
167
|
|
|
@@ -179,12 +179,12 @@ class OyiModel(BasePlatform):
|
|
|
179
179
|
self.messages.append({"role": "assistant", "content": response.text})
|
|
180
180
|
return response.text
|
|
181
181
|
else:
|
|
182
|
-
error_msg = f"
|
|
182
|
+
error_msg = f"Get response failed: {response.status_code}"
|
|
183
183
|
PrettyOutput.print(error_msg, OutputType.ERROR)
|
|
184
184
|
raise Exception(error_msg)
|
|
185
185
|
|
|
186
186
|
except Exception as e:
|
|
187
|
-
PrettyOutput.print(f"
|
|
187
|
+
PrettyOutput.print(f"Chat failed: {str(e)}", OutputType.ERROR)
|
|
188
188
|
raise e
|
|
189
189
|
|
|
190
190
|
def name(self) -> str:
|
|
@@ -225,16 +225,16 @@ class OyiModel(BasePlatform):
|
|
|
225
225
|
self.reset()
|
|
226
226
|
return True
|
|
227
227
|
else:
|
|
228
|
-
error_msg = f"
|
|
228
|
+
error_msg = f"Delete conversation failed: {data.get('message', 'Unknown error')}"
|
|
229
229
|
PrettyOutput.print(error_msg, OutputType.ERROR)
|
|
230
230
|
return False
|
|
231
231
|
else:
|
|
232
|
-
error_msg = f"
|
|
232
|
+
error_msg = f"Delete conversation request failed: {response.status_code}"
|
|
233
233
|
PrettyOutput.print(error_msg, OutputType.ERROR)
|
|
234
234
|
return False
|
|
235
235
|
|
|
236
236
|
except Exception as e:
|
|
237
|
-
PrettyOutput.print(f"
|
|
237
|
+
PrettyOutput.print(f"Delete conversation failed: {str(e)}", OutputType.ERROR)
|
|
238
238
|
return False
|
|
239
239
|
|
|
240
240
|
def upload_files(self, file_list: List[str]) -> List[Dict]:
|
|
@@ -250,7 +250,7 @@ class OyiModel(BasePlatform):
|
|
|
250
250
|
# 检查当前模型是否支持文件上传
|
|
251
251
|
model_info = self.models.get(self.model_name)
|
|
252
252
|
if not model_info or not model_info.get('uploadFile', False):
|
|
253
|
-
PrettyOutput.print(f"
|
|
253
|
+
PrettyOutput.print(f"The current model {self.model_name} does not support file upload", OutputType.WARNING)
|
|
254
254
|
return []
|
|
255
255
|
|
|
256
256
|
headers = {
|
|
@@ -266,7 +266,7 @@ class OyiModel(BasePlatform):
|
|
|
266
266
|
# 检查文件类型
|
|
267
267
|
file_type = mimetypes.guess_type(file_path)[0]
|
|
268
268
|
if not file_type or not file_type.startswith(('image/', 'text/', 'application/')):
|
|
269
|
-
PrettyOutput.print(f"
|
|
269
|
+
PrettyOutput.print(f"The file type {file_type} is not supported", OutputType.ERROR)
|
|
270
270
|
continue
|
|
271
271
|
|
|
272
272
|
with open(file_path, 'rb') as f:
|
|
@@ -285,22 +285,22 @@ class OyiModel(BasePlatform):
|
|
|
285
285
|
if data.get('code') == 200:
|
|
286
286
|
self.files.append(data)
|
|
287
287
|
else:
|
|
288
|
-
PrettyOutput.print(f"
|
|
288
|
+
PrettyOutput.print(f"File upload failed: {data.get('message')}", OutputType.ERROR)
|
|
289
289
|
return []
|
|
290
290
|
else:
|
|
291
|
-
PrettyOutput.print(f"
|
|
291
|
+
PrettyOutput.print(f"File upload failed: {response.status_code}", OutputType.ERROR)
|
|
292
292
|
return []
|
|
293
293
|
|
|
294
294
|
return self.files
|
|
295
295
|
except Exception as e:
|
|
296
|
-
PrettyOutput.print(f"
|
|
296
|
+
PrettyOutput.print(f"File upload failed: {str(e)}", OutputType.ERROR)
|
|
297
297
|
return []
|
|
298
298
|
|
|
299
299
|
def get_available_models(self) -> List[str]:
|
|
300
|
-
"""
|
|
300
|
+
"""Get available model list
|
|
301
301
|
|
|
302
302
|
Returns:
|
|
303
|
-
List[str]:
|
|
303
|
+
List[str]: Available model name list
|
|
304
304
|
"""
|
|
305
305
|
try:
|
|
306
306
|
if self.models:
|
|
@@ -320,7 +320,7 @@ class OyiModel(BasePlatform):
|
|
|
320
320
|
)
|
|
321
321
|
|
|
322
322
|
if response.status_code != 200:
|
|
323
|
-
PrettyOutput.print(f"
|
|
323
|
+
PrettyOutput.print(f"Get model list failed: {response.status_code}", OutputType.ERROR)
|
|
324
324
|
return []
|
|
325
325
|
|
|
326
326
|
data = response.json()
|
|
@@ -357,12 +357,12 @@ class OyiModel(BasePlatform):
|
|
|
357
357
|
|
|
358
358
|
# 添加文件上传支持标记
|
|
359
359
|
if model.get('uploadFile'):
|
|
360
|
-
model_str += " [
|
|
360
|
+
model_str += " [Support file upload]"
|
|
361
361
|
model['desc'] = model_str
|
|
362
362
|
models.append(model_name)
|
|
363
363
|
|
|
364
364
|
return sorted(models)
|
|
365
365
|
|
|
366
366
|
except Exception as e:
|
|
367
|
-
PrettyOutput.print(f"
|
|
367
|
+
PrettyOutput.print(f"Get model list failed: {str(e)}", OutputType.WARNING)
|
|
368
368
|
return []
|
jarvis/models/registry.py
CHANGED
|
@@ -19,7 +19,7 @@ REQUIRED_METHODS = [
|
|
|
19
19
|
]
|
|
20
20
|
|
|
21
21
|
class PlatformRegistry:
|
|
22
|
-
"""
|
|
22
|
+
"""Platform registry"""
|
|
23
23
|
|
|
24
24
|
global_platform_name = "kimi"
|
|
25
25
|
global_platform_registry = None
|
|
@@ -37,19 +37,19 @@ class PlatformRegistry:
|
|
|
37
37
|
|
|
38
38
|
pass
|
|
39
39
|
except Exception as e:
|
|
40
|
-
PrettyOutput.print(f"
|
|
40
|
+
PrettyOutput.print(f"Create platform directory failed: {str(e)}", OutputType.ERROR)
|
|
41
41
|
return ""
|
|
42
42
|
return user_platform_dir
|
|
43
43
|
|
|
44
44
|
@staticmethod
|
|
45
45
|
def check_platform_implementation(platform_class: Type[BasePlatform]) -> bool:
|
|
46
|
-
"""
|
|
46
|
+
"""Check if the platform class implements all necessary methods
|
|
47
47
|
|
|
48
48
|
Args:
|
|
49
|
-
platform_class:
|
|
49
|
+
platform_class: The platform class to check
|
|
50
50
|
|
|
51
51
|
Returns:
|
|
52
|
-
bool:
|
|
52
|
+
bool: Whether all necessary methods are implemented
|
|
53
53
|
"""
|
|
54
54
|
missing_methods = []
|
|
55
55
|
|
|
@@ -68,11 +68,11 @@ class PlatformRegistry:
|
|
|
68
68
|
sig = inspect.signature(method)
|
|
69
69
|
method_params = [p for p in sig.parameters if p != 'self']
|
|
70
70
|
if len(method_params) != len(params):
|
|
71
|
-
missing_methods.append(f"{method_name}(
|
|
71
|
+
missing_methods.append(f"{method_name}(parameter mismatch)")
|
|
72
72
|
|
|
73
73
|
if missing_methods:
|
|
74
74
|
PrettyOutput.print(
|
|
75
|
-
f"
|
|
75
|
+
f"Platform {platform_class.__name__} is missing necessary methods: {', '.join(missing_methods)}",
|
|
76
76
|
OutputType.ERROR
|
|
77
77
|
)
|
|
78
78
|
return False
|
|
@@ -81,19 +81,19 @@ class PlatformRegistry:
|
|
|
81
81
|
|
|
82
82
|
@staticmethod
|
|
83
83
|
def load_platform_from_dir(directory: str) -> Dict[str, Type[BasePlatform]]:
|
|
84
|
-
"""
|
|
84
|
+
"""Load platforms from specified directory
|
|
85
85
|
|
|
86
86
|
Args:
|
|
87
|
-
directory:
|
|
87
|
+
directory: Platform directory path
|
|
88
88
|
|
|
89
89
|
Returns:
|
|
90
|
-
Dict[str, Type[BasePlatform]]:
|
|
90
|
+
Dict[str, Type[BasePlatform]]: Platform name to platform class mapping
|
|
91
91
|
"""
|
|
92
92
|
platforms = {}
|
|
93
93
|
|
|
94
94
|
# 确保目录存在
|
|
95
95
|
if not os.path.exists(directory):
|
|
96
|
-
PrettyOutput.print(f"
|
|
96
|
+
PrettyOutput.print(f"Platform directory does not exist: {directory}", OutputType.ERROR)
|
|
97
97
|
return platforms
|
|
98
98
|
|
|
99
99
|
# 获取目录的包名
|
|
@@ -127,18 +127,18 @@ class PlatformRegistry:
|
|
|
127
127
|
if not PlatformRegistry.check_platform_implementation(obj):
|
|
128
128
|
continue
|
|
129
129
|
if not PlatformRegistry.suppress_output:
|
|
130
|
-
PrettyOutput.print(f"
|
|
131
|
-
platforms[obj.platform_name] = obj
|
|
130
|
+
PrettyOutput.print(f"Load platform from {os.path.join(directory, filename)}: {obj.platform_name}", OutputType.SUCCESS) # type: ignore
|
|
131
|
+
platforms[obj.platform_name] = obj # type: ignore
|
|
132
132
|
break
|
|
133
133
|
except Exception as e:
|
|
134
|
-
PrettyOutput.print(f"
|
|
134
|
+
PrettyOutput.print(f"Load platform {module_name} failed: {str(e)}", OutputType.ERROR)
|
|
135
135
|
|
|
136
136
|
return platforms
|
|
137
137
|
|
|
138
138
|
|
|
139
139
|
@staticmethod
|
|
140
140
|
def get_global_platform_registry():
|
|
141
|
-
"""
|
|
141
|
+
"""Get global platform registry"""
|
|
142
142
|
if PlatformRegistry.global_platform_registry is None:
|
|
143
143
|
PlatformRegistry.global_platform_registry = PlatformRegistry()
|
|
144
144
|
|
|
@@ -154,58 +154,57 @@ class PlatformRegistry:
|
|
|
154
154
|
return PlatformRegistry.global_platform_registry
|
|
155
155
|
|
|
156
156
|
def __init__(self):
|
|
157
|
-
"""
|
|
158
|
-
"""
|
|
157
|
+
"""Initialize platform registry"""
|
|
159
158
|
self.platforms: Dict[str, Type[BasePlatform]] = {}
|
|
160
159
|
|
|
161
160
|
def get_normal_platform(self) -> BasePlatform:
|
|
162
161
|
platform_name = os.environ.get("JARVIS_PLATFORM", "kimi")
|
|
163
162
|
model_name = os.environ.get("JARVIS_MODEL", "kimi")
|
|
164
163
|
platform = self.create_platform(platform_name)
|
|
165
|
-
platform.set_model_name(model_name)
|
|
166
|
-
return platform
|
|
164
|
+
platform.set_model_name(model_name) # type: ignore
|
|
165
|
+
return platform # type: ignore
|
|
167
166
|
|
|
168
167
|
def get_codegen_platform(self) -> BasePlatform:
|
|
169
168
|
platform_name = os.environ.get("JARVIS_CODEGEN_PLATFORM", os.environ.get("JARVIS_PLATFORM", "kimi"))
|
|
170
169
|
model_name = os.environ.get("JARVIS_CODEGEN_MODEL", os.environ.get("JARVIS_MODEL", "kimi"))
|
|
171
170
|
platform = self.create_platform(platform_name)
|
|
172
|
-
platform.set_model_name(model_name)
|
|
173
|
-
return platform
|
|
171
|
+
platform.set_model_name(model_name) # type: ignore
|
|
172
|
+
return platform # type: ignore
|
|
174
173
|
|
|
175
174
|
def get_cheap_platform(self) -> BasePlatform:
|
|
176
175
|
platform_name = os.environ.get("JARVIS_CHEAP_PLATFORM", os.environ.get("JARVIS_PLATFORM", "kimi"))
|
|
177
176
|
model_name = os.environ.get("JARVIS_CHEAP_MODEL", os.environ.get("JARVIS_MODEL", "kimi"))
|
|
178
177
|
platform = self.create_platform(platform_name)
|
|
179
|
-
platform.set_model_name(model_name)
|
|
180
|
-
return platform
|
|
178
|
+
platform.set_model_name(model_name) # type: ignore
|
|
179
|
+
return platform # type: ignore
|
|
181
180
|
|
|
182
181
|
def get_thinking_platform(self) -> BasePlatform:
|
|
183
182
|
platform_name = os.environ.get("JARVIS_THINKING_PLATFORM", os.environ.get("JARVIS_PLATFORM", "kimi"))
|
|
184
183
|
model_name = os.environ.get("JARVIS_THINKING_MODEL", os.environ.get("JARVIS_MODEL", "kimi"))
|
|
185
184
|
platform = self.create_platform(platform_name)
|
|
186
|
-
platform.set_model_name(model_name)
|
|
187
|
-
return platform
|
|
185
|
+
platform.set_model_name(model_name) # type: ignore
|
|
186
|
+
return platform # type: ignore
|
|
188
187
|
|
|
189
188
|
def register_platform(self, name: str, platform_class: Type[BasePlatform]):
|
|
190
|
-
"""
|
|
189
|
+
"""Register platform class
|
|
191
190
|
|
|
192
191
|
Args:
|
|
193
|
-
name:
|
|
194
|
-
model_class:
|
|
192
|
+
name: Platform name
|
|
193
|
+
model_class: Platform class
|
|
195
194
|
"""
|
|
196
195
|
self.platforms[name] = platform_class
|
|
197
196
|
|
|
198
197
|
def create_platform(self, name: str) -> Optional[BasePlatform]:
|
|
199
|
-
"""
|
|
198
|
+
"""Create platform instance
|
|
200
199
|
|
|
201
200
|
Args:
|
|
202
|
-
name:
|
|
201
|
+
name: Platform name
|
|
203
202
|
|
|
204
203
|
Returns:
|
|
205
|
-
BasePlatform:
|
|
204
|
+
BasePlatform: Platform instance
|
|
206
205
|
"""
|
|
207
206
|
if name not in self.platforms:
|
|
208
|
-
PrettyOutput.print(f"
|
|
207
|
+
PrettyOutput.print(f"Platform not found: {name}", OutputType.ERROR)
|
|
209
208
|
return None
|
|
210
209
|
|
|
211
210
|
try:
|
|
@@ -213,10 +212,10 @@ class PlatformRegistry:
|
|
|
213
212
|
platform = self.platforms[name]()
|
|
214
213
|
return platform
|
|
215
214
|
except Exception as e:
|
|
216
|
-
PrettyOutput.print(f"
|
|
215
|
+
PrettyOutput.print(f"Create platform failed: {str(e)}", OutputType.ERROR)
|
|
217
216
|
return None
|
|
218
217
|
|
|
219
218
|
def get_available_platforms(self) -> List[str]:
|
|
220
|
-
"""
|
|
219
|
+
"""Get available platform list"""
|
|
221
220
|
return list(self.platforms.keys())
|
|
222
221
|
|
jarvis/tools/ask_user.py
CHANGED
|
@@ -4,13 +4,13 @@ from jarvis.utils import get_multiline_input, PrettyOutput, OutputType
|
|
|
4
4
|
|
|
5
5
|
class AskUserTool:
|
|
6
6
|
name="ask_user"
|
|
7
|
-
description="""
|
|
7
|
+
description="""Ask the user when information needed to complete the task is missing or when critical decision information is lacking. Users can input multiple lines of text, ending with an empty line. Use cases: 1. Need user to provide more information to complete the task; 2. Need user to make critical decisions; 3. Need user to confirm important operations; 4. Need user to provide additional information"""
|
|
8
8
|
parameters={
|
|
9
9
|
"type": "object",
|
|
10
10
|
"properties": {
|
|
11
11
|
"question": {
|
|
12
12
|
"type": "string",
|
|
13
|
-
"description": "
|
|
13
|
+
"description": "The question to ask the user"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"required": ["question"]
|
|
@@ -34,12 +34,12 @@ class AskUserTool:
|
|
|
34
34
|
PrettyOutput.print(question, OutputType.SYSTEM)
|
|
35
35
|
|
|
36
36
|
# 获取用户输入
|
|
37
|
-
user_response = get_multiline_input("
|
|
37
|
+
user_response = get_multiline_input("Please enter your answer (input empty line to end)")
|
|
38
38
|
|
|
39
39
|
if user_response == "__interrupt__":
|
|
40
40
|
return {
|
|
41
41
|
"success": False,
|
|
42
|
-
"error": "
|
|
42
|
+
"error": "User canceled input"
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
return {
|
|
@@ -50,5 +50,5 @@ class AskUserTool:
|
|
|
50
50
|
except Exception as e:
|
|
51
51
|
return {
|
|
52
52
|
"success": False,
|
|
53
|
-
"error": f"
|
|
53
|
+
"error": f"Failed to ask user: {str(e)}"
|
|
54
54
|
}
|
jarvis/tools/base.py
CHANGED
|
@@ -11,7 +11,7 @@ class Tool:
|
|
|
11
11
|
self.func = func
|
|
12
12
|
|
|
13
13
|
def to_dict(self) -> Dict:
|
|
14
|
-
"""
|
|
14
|
+
"""Convert to tool format"""
|
|
15
15
|
return {
|
|
16
16
|
"name": self.name,
|
|
17
17
|
"description": self.description,
|
|
@@ -19,5 +19,5 @@ class Tool:
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
def execute(self, arguments: Dict) -> Dict[str, Any]:
|
|
22
|
-
"""
|
|
22
|
+
"""Execute tool function"""
|
|
23
23
|
return self.func(arguments)
|