jarvis-ai-assistant 0.1.222__py3-none-any.whl → 0.7.0__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +1143 -245
- jarvis/jarvis_agent/agent_manager.py +97 -0
- jarvis/jarvis_agent/builtin_input_handler.py +12 -10
- jarvis/jarvis_agent/config_editor.py +57 -0
- jarvis/jarvis_agent/edit_file_handler.py +392 -99
- jarvis/jarvis_agent/event_bus.py +48 -0
- jarvis/jarvis_agent/events.py +157 -0
- jarvis/jarvis_agent/file_context_handler.py +79 -0
- jarvis/jarvis_agent/file_methodology_manager.py +117 -0
- jarvis/jarvis_agent/jarvis.py +1117 -147
- jarvis/jarvis_agent/main.py +78 -34
- jarvis/jarvis_agent/memory_manager.py +195 -0
- jarvis/jarvis_agent/methodology_share_manager.py +174 -0
- jarvis/jarvis_agent/prompt_manager.py +82 -0
- jarvis/jarvis_agent/prompts.py +46 -9
- jarvis/jarvis_agent/protocols.py +4 -1
- jarvis/jarvis_agent/rewrite_file_handler.py +141 -0
- jarvis/jarvis_agent/run_loop.py +146 -0
- jarvis/jarvis_agent/session_manager.py +9 -9
- jarvis/jarvis_agent/share_manager.py +228 -0
- jarvis/jarvis_agent/shell_input_handler.py +23 -3
- jarvis/jarvis_agent/stdio_redirect.py +295 -0
- jarvis/jarvis_agent/task_analyzer.py +212 -0
- jarvis/jarvis_agent/task_manager.py +154 -0
- jarvis/jarvis_agent/task_planner.py +496 -0
- jarvis/jarvis_agent/tool_executor.py +8 -4
- jarvis/jarvis_agent/tool_share_manager.py +139 -0
- jarvis/jarvis_agent/user_interaction.py +42 -0
- jarvis/jarvis_agent/utils.py +54 -0
- jarvis/jarvis_agent/web_bridge.py +189 -0
- jarvis/jarvis_agent/web_output_sink.py +53 -0
- jarvis/jarvis_agent/web_server.py +751 -0
- jarvis/jarvis_c2rust/__init__.py +26 -0
- jarvis/jarvis_c2rust/cli.py +613 -0
- jarvis/jarvis_c2rust/collector.py +258 -0
- jarvis/jarvis_c2rust/library_replacer.py +1122 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +1300 -0
- jarvis/jarvis_c2rust/optimizer.py +960 -0
- jarvis/jarvis_c2rust/scanner.py +1681 -0
- jarvis/jarvis_c2rust/transpiler.py +2325 -0
- jarvis/jarvis_code_agent/build_validation_config.py +133 -0
- jarvis/jarvis_code_agent/code_agent.py +1605 -178
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +62 -0
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +102 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +59 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +69 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +38 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +38 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +50 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +93 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +129 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +54 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +154 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +363 -0
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +89 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +31 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +231 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +183 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +219 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +209 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +451 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +77 -0
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +48 -0
- jarvis/jarvis_code_agent/lint.py +275 -13
- jarvis/jarvis_code_agent/utils.py +142 -0
- jarvis/jarvis_code_analysis/checklists/loader.py +20 -6
- jarvis/jarvis_code_analysis/code_review.py +583 -548
- jarvis/jarvis_data/config_schema.json +339 -28
- jarvis/jarvis_git_squash/main.py +22 -13
- jarvis/jarvis_git_utils/git_commiter.py +171 -55
- jarvis/jarvis_mcp/sse_mcp_client.py +22 -15
- jarvis/jarvis_mcp/stdio_mcp_client.py +4 -4
- jarvis/jarvis_mcp/streamable_mcp_client.py +36 -16
- jarvis/jarvis_memory_organizer/memory_organizer.py +753 -0
- jarvis/jarvis_methodology/main.py +48 -63
- jarvis/jarvis_multi_agent/__init__.py +302 -43
- jarvis/jarvis_multi_agent/main.py +70 -24
- jarvis/jarvis_platform/ai8.py +40 -23
- jarvis/jarvis_platform/base.py +210 -49
- jarvis/jarvis_platform/human.py +11 -1
- jarvis/jarvis_platform/kimi.py +82 -76
- jarvis/jarvis_platform/openai.py +73 -1
- jarvis/jarvis_platform/registry.py +8 -15
- jarvis/jarvis_platform/tongyi.py +115 -101
- jarvis/jarvis_platform/yuanbao.py +89 -63
- jarvis/jarvis_platform_manager/main.py +194 -132
- jarvis/jarvis_platform_manager/service.py +122 -86
- jarvis/jarvis_rag/cli.py +156 -53
- jarvis/jarvis_rag/embedding_manager.py +155 -12
- jarvis/jarvis_rag/llm_interface.py +10 -13
- jarvis/jarvis_rag/query_rewriter.py +63 -12
- jarvis/jarvis_rag/rag_pipeline.py +222 -40
- jarvis/jarvis_rag/reranker.py +26 -3
- jarvis/jarvis_rag/retriever.py +270 -14
- jarvis/jarvis_sec/__init__.py +3605 -0
- jarvis/jarvis_sec/checkers/__init__.py +32 -0
- jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
- jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
- jarvis/jarvis_sec/cli.py +116 -0
- jarvis/jarvis_sec/report.py +257 -0
- jarvis/jarvis_sec/status.py +264 -0
- jarvis/jarvis_sec/types.py +20 -0
- jarvis/jarvis_sec/workflow.py +219 -0
- jarvis/jarvis_smart_shell/main.py +405 -137
- jarvis/jarvis_stats/__init__.py +13 -0
- jarvis/jarvis_stats/cli.py +387 -0
- jarvis/jarvis_stats/stats.py +711 -0
- jarvis/jarvis_stats/storage.py +612 -0
- jarvis/jarvis_stats/visualizer.py +282 -0
- jarvis/jarvis_tools/ask_user.py +1 -0
- jarvis/jarvis_tools/base.py +18 -2
- jarvis/jarvis_tools/clear_memory.py +239 -0
- jarvis/jarvis_tools/cli/main.py +220 -144
- jarvis/jarvis_tools/execute_script.py +52 -12
- jarvis/jarvis_tools/file_analyzer.py +17 -12
- jarvis/jarvis_tools/generate_new_tool.py +46 -24
- jarvis/jarvis_tools/read_code.py +277 -18
- jarvis/jarvis_tools/read_symbols.py +141 -0
- jarvis/jarvis_tools/read_webpage.py +86 -13
- jarvis/jarvis_tools/registry.py +294 -90
- jarvis/jarvis_tools/retrieve_memory.py +227 -0
- jarvis/jarvis_tools/save_memory.py +194 -0
- jarvis/jarvis_tools/search_web.py +62 -28
- jarvis/jarvis_tools/sub_agent.py +205 -0
- jarvis/jarvis_tools/sub_code_agent.py +217 -0
- jarvis/jarvis_tools/virtual_tty.py +330 -62
- jarvis/jarvis_utils/builtin_replace_map.py +4 -5
- jarvis/jarvis_utils/clipboard.py +90 -0
- jarvis/jarvis_utils/config.py +607 -50
- jarvis/jarvis_utils/embedding.py +3 -0
- jarvis/jarvis_utils/fzf.py +57 -0
- jarvis/jarvis_utils/git_utils.py +251 -29
- jarvis/jarvis_utils/globals.py +174 -17
- jarvis/jarvis_utils/http.py +58 -79
- jarvis/jarvis_utils/input.py +899 -153
- jarvis/jarvis_utils/methodology.py +210 -83
- jarvis/jarvis_utils/output.py +220 -137
- jarvis/jarvis_utils/utils.py +1906 -135
- jarvis_ai_assistant-0.7.0.dist-info/METADATA +465 -0
- jarvis_ai_assistant-0.7.0.dist-info/RECORD +192 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/entry_points.txt +8 -2
- jarvis/jarvis_git_details/main.py +0 -265
- jarvis/jarvis_platform/oyi.py +0 -357
- jarvis/jarvis_tools/edit_file.py +0 -255
- jarvis/jarvis_tools/rewrite_file.py +0 -195
- jarvis_ai_assistant-0.1.222.dist-info/METADATA +0 -767
- jarvis_ai_assistant-0.1.222.dist-info/RECORD +0 -110
- /jarvis/{jarvis_git_details → jarvis_memory_organizer}/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/top_level.txt +0 -0
jarvis/jarvis_platform/oyi.py
DELETED
|
@@ -1,357 +0,0 @@
|
|
|
1
|
-
import mimetypes
|
|
2
|
-
import os
|
|
3
|
-
from typing import Dict, Generator, List, Tuple
|
|
4
|
-
from jarvis.jarvis_platform.base import BasePlatform
|
|
5
|
-
import json
|
|
6
|
-
|
|
7
|
-
from jarvis.jarvis_utils import http
|
|
8
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
9
|
-
from jarvis.jarvis_utils.utils import while_success
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class OyiModel(BasePlatform):
|
|
13
|
-
"""Oyi model implementation"""
|
|
14
|
-
|
|
15
|
-
BASE_URL = "https://api-10086.rcouyi.com"
|
|
16
|
-
|
|
17
|
-
def get_model_list(self) -> List[Tuple[str, str]]:
|
|
18
|
-
"""Get model list"""
|
|
19
|
-
self.get_available_models()
|
|
20
|
-
return [(name, info["desc"]) for name, info in self.models.items()]
|
|
21
|
-
|
|
22
|
-
def __init__(self):
|
|
23
|
-
"""Initialize model"""
|
|
24
|
-
super().__init__()
|
|
25
|
-
self.models = {}
|
|
26
|
-
self.messages = []
|
|
27
|
-
self.system_prompt = ""
|
|
28
|
-
self.conversation = None
|
|
29
|
-
self.first_chat = True
|
|
30
|
-
|
|
31
|
-
self.token = os.getenv("OYI_API_KEY")
|
|
32
|
-
if not self.token:
|
|
33
|
-
PrettyOutput.print("OYI_API_KEY 未设置", OutputType.WARNING)
|
|
34
|
-
|
|
35
|
-
self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
|
|
36
|
-
if self.model_name not in [m.split()[0] for m in self.get_available_models()]:
|
|
37
|
-
PrettyOutput.print(
|
|
38
|
-
f"警告: 选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
def set_model_name(self, model_name: str):
|
|
42
|
-
"""Set model name"""
|
|
43
|
-
|
|
44
|
-
self.model_name = model_name
|
|
45
|
-
|
|
46
|
-
def create_conversation(self) -> bool:
|
|
47
|
-
"""Create a new conversation"""
|
|
48
|
-
try:
|
|
49
|
-
headers = {
|
|
50
|
-
"Authorization": f"Bearer {self.token}",
|
|
51
|
-
"Content-Type": "application/json",
|
|
52
|
-
"Accept": "application/json",
|
|
53
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
payload = {
|
|
57
|
-
"id": 0,
|
|
58
|
-
"roleId": 0,
|
|
59
|
-
"title": "New conversation",
|
|
60
|
-
"isLock": False,
|
|
61
|
-
"systemMessage": "",
|
|
62
|
-
"params": json.dumps(
|
|
63
|
-
{
|
|
64
|
-
"model": self.model_name,
|
|
65
|
-
"is_webSearch": True,
|
|
66
|
-
"message": [],
|
|
67
|
-
"systemMessage": None,
|
|
68
|
-
"requestMsgCount": 65536,
|
|
69
|
-
"temperature": 0.8,
|
|
70
|
-
"speechVoice": "Alloy",
|
|
71
|
-
"max_tokens": 8192,
|
|
72
|
-
"chatPluginIds": [],
|
|
73
|
-
}
|
|
74
|
-
),
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
response = while_success(
|
|
78
|
-
lambda: http.post(
|
|
79
|
-
f"{self.BASE_URL}/chatapi/chat/save", headers=headers, json=payload
|
|
80
|
-
),
|
|
81
|
-
sleep_time=5,
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
data = response.json()
|
|
85
|
-
if data["code"] == 200 and data["type"] == "success":
|
|
86
|
-
self.conversation = data
|
|
87
|
-
return True
|
|
88
|
-
else:
|
|
89
|
-
PrettyOutput.print(
|
|
90
|
-
f"创建会话失败: {data['message']}", OutputType.WARNING
|
|
91
|
-
)
|
|
92
|
-
return False
|
|
93
|
-
|
|
94
|
-
except Exception as e:
|
|
95
|
-
PrettyOutput.print(f"创建会话失败: {str(e)}", OutputType.ERROR)
|
|
96
|
-
return False
|
|
97
|
-
|
|
98
|
-
def set_system_prompt(self, message: str):
|
|
99
|
-
"""Set system message"""
|
|
100
|
-
self.system_prompt = message
|
|
101
|
-
|
|
102
|
-
def chat(self, message: str) -> Generator[str, None, None]:
|
|
103
|
-
"""Execute chat with the model
|
|
104
|
-
|
|
105
|
-
Args:
|
|
106
|
-
message: User input message
|
|
107
|
-
|
|
108
|
-
Returns:
|
|
109
|
-
str: Model response
|
|
110
|
-
"""
|
|
111
|
-
try:
|
|
112
|
-
# 确保有会话ID
|
|
113
|
-
if not self.conversation:
|
|
114
|
-
if not self.create_conversation():
|
|
115
|
-
raise Exception("Failed to create conversation")
|
|
116
|
-
|
|
117
|
-
# 1. 发送消息
|
|
118
|
-
headers = {
|
|
119
|
-
"Authorization": f"Bearer {self.token}",
|
|
120
|
-
"Content-Type": "application/json",
|
|
121
|
-
"Accept": "application/json, text/plain, */*",
|
|
122
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
|
123
|
-
"Origin": "https://ai.rcouyi.com",
|
|
124
|
-
"Referer": "https://ai.rcouyi.com/",
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
payload = {
|
|
128
|
-
"topicId": (
|
|
129
|
-
self.conversation["result"]["id"] if self.conversation else None
|
|
130
|
-
),
|
|
131
|
-
"messages": self.messages,
|
|
132
|
-
"content": message,
|
|
133
|
-
"contentFiles": [],
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
# 如果有上传的文件,添加到请求中
|
|
137
|
-
if self.first_chat:
|
|
138
|
-
message = self.system_prompt + "\n" + message
|
|
139
|
-
payload["content"] = message
|
|
140
|
-
self.first_chat = False
|
|
141
|
-
|
|
142
|
-
self.messages.append({"role": "user", "content": message})
|
|
143
|
-
|
|
144
|
-
# 发送消息
|
|
145
|
-
response = while_success(
|
|
146
|
-
lambda: http.post(
|
|
147
|
-
f"{self.BASE_URL}/chatapi/chat/message",
|
|
148
|
-
headers=headers,
|
|
149
|
-
json=payload,
|
|
150
|
-
),
|
|
151
|
-
sleep_time=5,
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
data = response.json()
|
|
155
|
-
if data["code"] != 200 or data["type"] != "success":
|
|
156
|
-
error_msg = f"聊天失败: {data.get('message', '未知错误')}"
|
|
157
|
-
PrettyOutput.print(error_msg, OutputType.WARNING)
|
|
158
|
-
raise Exception(error_msg)
|
|
159
|
-
|
|
160
|
-
message_id = data["result"][-1]
|
|
161
|
-
|
|
162
|
-
# 获取响应内容
|
|
163
|
-
response = while_success(
|
|
164
|
-
lambda: http.stream_post(
|
|
165
|
-
f"{self.BASE_URL}/chatapi/chat/message/{message_id}",
|
|
166
|
-
headers=headers,
|
|
167
|
-
),
|
|
168
|
-
sleep_time=5,
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
full_response = ""
|
|
172
|
-
bin = b""
|
|
173
|
-
for chunk in response:
|
|
174
|
-
if chunk:
|
|
175
|
-
bin += chunk
|
|
176
|
-
try:
|
|
177
|
-
text = bin.decode("utf-8")
|
|
178
|
-
except UnicodeDecodeError:
|
|
179
|
-
continue
|
|
180
|
-
full_response += text
|
|
181
|
-
bin = b""
|
|
182
|
-
yield text
|
|
183
|
-
|
|
184
|
-
self.messages.append({"role": "assistant", "content": full_response})
|
|
185
|
-
return None
|
|
186
|
-
except Exception as e:
|
|
187
|
-
PrettyOutput.print(f"聊天失败: {str(e)}", OutputType.ERROR)
|
|
188
|
-
raise e
|
|
189
|
-
|
|
190
|
-
def name(self) -> str:
|
|
191
|
-
"""Return model name"""
|
|
192
|
-
return self.model_name
|
|
193
|
-
|
|
194
|
-
@classmethod
|
|
195
|
-
def platform_name(cls) -> str:
|
|
196
|
-
"""Return platform name"""
|
|
197
|
-
return "oyi"
|
|
198
|
-
|
|
199
|
-
def delete_chat(self) -> bool:
|
|
200
|
-
"""Delete current chat session"""
|
|
201
|
-
try:
|
|
202
|
-
if not self.conversation:
|
|
203
|
-
return True
|
|
204
|
-
|
|
205
|
-
headers = {
|
|
206
|
-
"Authorization": f"Bearer {self.token}",
|
|
207
|
-
"Content-Type": "application/json",
|
|
208
|
-
"Accept": "application/json, text/plain, */*",
|
|
209
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
|
210
|
-
"Origin": "https://ai.rcouyi.com",
|
|
211
|
-
"Referer": "https://ai.rcouyi.com/",
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
response = while_success(
|
|
215
|
-
lambda: http.post(
|
|
216
|
-
f"{self.BASE_URL}/chatapi/chat/{self.conversation['result']['id']}", # type: ignore
|
|
217
|
-
headers=headers,
|
|
218
|
-
json={},
|
|
219
|
-
),
|
|
220
|
-
sleep_time=5,
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
data = response.json()
|
|
224
|
-
if data["code"] == 200 and data["type"] == "success":
|
|
225
|
-
self.messages = []
|
|
226
|
-
self.conversation = None
|
|
227
|
-
self.first_chat = True
|
|
228
|
-
return True
|
|
229
|
-
else:
|
|
230
|
-
error_msg = f"删除会话失败: {data.get('message', '未知错误')}"
|
|
231
|
-
PrettyOutput.print(error_msg, OutputType.WARNING)
|
|
232
|
-
return False
|
|
233
|
-
|
|
234
|
-
except Exception as e:
|
|
235
|
-
PrettyOutput.print(f"删除会话失败: {str(e)}", OutputType.ERROR)
|
|
236
|
-
return False
|
|
237
|
-
|
|
238
|
-
def save(self, file_path: str) -> bool:
|
|
239
|
-
"""Save chat session to a file."""
|
|
240
|
-
if not self.conversation:
|
|
241
|
-
PrettyOutput.print("没有活动的会话可供保存", OutputType.WARNING)
|
|
242
|
-
return False
|
|
243
|
-
|
|
244
|
-
state = {
|
|
245
|
-
"conversation": self.conversation,
|
|
246
|
-
"messages": self.messages,
|
|
247
|
-
"model_name": self.model_name,
|
|
248
|
-
"system_prompt": self.system_prompt,
|
|
249
|
-
"first_chat": self.first_chat,
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
try:
|
|
253
|
-
with open(file_path, "w", encoding="utf-8") as f:
|
|
254
|
-
json.dump(state, f, ensure_ascii=False, indent=4)
|
|
255
|
-
self._saved = True
|
|
256
|
-
PrettyOutput.print(f"会话已成功保存到 {file_path}", OutputType.SUCCESS)
|
|
257
|
-
return True
|
|
258
|
-
except Exception as e:
|
|
259
|
-
PrettyOutput.print(f"保存会话失败: {str(e)}", OutputType.ERROR)
|
|
260
|
-
return False
|
|
261
|
-
|
|
262
|
-
def restore(self, file_path: str) -> bool:
|
|
263
|
-
"""Restore chat session from a file."""
|
|
264
|
-
try:
|
|
265
|
-
with open(file_path, "r", encoding="utf-8") as f:
|
|
266
|
-
state = json.load(f)
|
|
267
|
-
|
|
268
|
-
self.conversation = state.get("conversation")
|
|
269
|
-
self.messages = state.get("messages", [])
|
|
270
|
-
self.model_name = state.get("model_name", "deepseek-chat")
|
|
271
|
-
self.system_prompt = state.get("system_prompt", "")
|
|
272
|
-
self.first_chat = state.get("first_chat", True)
|
|
273
|
-
self._saved = True
|
|
274
|
-
|
|
275
|
-
PrettyOutput.print(f"从 {file_path} 成功恢复会话", OutputType.SUCCESS)
|
|
276
|
-
return True
|
|
277
|
-
except FileNotFoundError:
|
|
278
|
-
PrettyOutput.print(f"会话文件未找到: {file_path}", OutputType.ERROR)
|
|
279
|
-
return False
|
|
280
|
-
except Exception as e:
|
|
281
|
-
PrettyOutput.print(f"恢复会话失败: {str(e)}", OutputType.ERROR)
|
|
282
|
-
return False
|
|
283
|
-
|
|
284
|
-
def get_available_models(self) -> List[str]:
|
|
285
|
-
"""Get available model list
|
|
286
|
-
|
|
287
|
-
Returns:
|
|
288
|
-
List[str]: Available model name list
|
|
289
|
-
"""
|
|
290
|
-
try:
|
|
291
|
-
if self.models:
|
|
292
|
-
return list(self.models.keys())
|
|
293
|
-
|
|
294
|
-
headers = {
|
|
295
|
-
"Content-Type": "application/json",
|
|
296
|
-
"Accept": "application/json, text/plain, */*",
|
|
297
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
|
298
|
-
"Origin": "https://ai.rcouyi.com",
|
|
299
|
-
"Referer": "https://ai.rcouyi.com/",
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
response = while_success(
|
|
303
|
-
lambda: http.get(
|
|
304
|
-
"https://ai.rcouyi.com/config/system.json", headers=headers
|
|
305
|
-
),
|
|
306
|
-
sleep_time=5,
|
|
307
|
-
)
|
|
308
|
-
|
|
309
|
-
data = response.json()
|
|
310
|
-
|
|
311
|
-
# 保存模型信息
|
|
312
|
-
self.models = {
|
|
313
|
-
model["value"]: model
|
|
314
|
-
for model in data.get("model", [])
|
|
315
|
-
if model.get("enable", False) # 只保存启用的模型
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
# 格式化显示
|
|
319
|
-
models = []
|
|
320
|
-
for model in self.models.values():
|
|
321
|
-
# 基本信息
|
|
322
|
-
model_name = model["value"]
|
|
323
|
-
model_str = model["label"]
|
|
324
|
-
|
|
325
|
-
# 添加后缀标签
|
|
326
|
-
suffix = model.get("suffix", [])
|
|
327
|
-
if suffix:
|
|
328
|
-
# 处理新格式的suffix (字典列表)
|
|
329
|
-
if suffix and isinstance(suffix[0], dict):
|
|
330
|
-
suffix_str = ", ".join(s.get("tag", "") for s in suffix)
|
|
331
|
-
# 处理旧格式的suffix (字符串列表)
|
|
332
|
-
else:
|
|
333
|
-
suffix_str = ", ".join(str(s) for s in suffix)
|
|
334
|
-
model_str += f" ({suffix_str})"
|
|
335
|
-
|
|
336
|
-
# 添加描述或提示
|
|
337
|
-
info = model.get("tooltip") or model.get("description", "")
|
|
338
|
-
if info:
|
|
339
|
-
model_str += f" - {info}"
|
|
340
|
-
|
|
341
|
-
model["desc"] = model_str
|
|
342
|
-
models.append(model_name)
|
|
343
|
-
|
|
344
|
-
return sorted(models)
|
|
345
|
-
|
|
346
|
-
except Exception as e:
|
|
347
|
-
PrettyOutput.print(f"获取模型列表失败: {str(e)}", OutputType.WARNING)
|
|
348
|
-
return []
|
|
349
|
-
|
|
350
|
-
def support_upload_files(self) -> bool:
|
|
351
|
-
return False
|
|
352
|
-
|
|
353
|
-
def support_web(self) -> bool:
|
|
354
|
-
return False
|
|
355
|
-
|
|
356
|
-
def upload_files(self, file_list: List[str]) -> bool:
|
|
357
|
-
return False
|
jarvis/jarvis_tools/edit_file.py
DELETED
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
文件编辑工具类
|
|
4
|
-
|
|
5
|
-
功能概述:
|
|
6
|
-
1. 提供精确的文件内容搜索和替换功能,支持多组修改
|
|
7
|
-
2. 支持单个文件的编辑操作,包括创建新文件
|
|
8
|
-
3. 实现原子操作:所有修改要么全部成功,要么全部回滚
|
|
9
|
-
4. 严格匹配控制:每个搜索文本必须且只能匹配一次
|
|
10
|
-
|
|
11
|
-
核心特性:
|
|
12
|
-
- 支持不存在的文件和空文件处理
|
|
13
|
-
- 自动创建所需目录结构
|
|
14
|
-
- 完善的错误处理和回滚机制
|
|
15
|
-
- 严格的格式保持要求
|
|
16
|
-
"""
|
|
17
|
-
from typing import Any, Dict
|
|
18
|
-
|
|
19
|
-
from jarvis.jarvis_agent.edit_file_handler import EditFileHandler
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class FileSearchReplaceTool:
|
|
23
|
-
name = "edit_file"
|
|
24
|
-
description = """代码编辑工具,用于精确修改一个或多个文件
|
|
25
|
-
|
|
26
|
-
# 文件编辑工具使用指南
|
|
27
|
-
|
|
28
|
-
## 基本使用
|
|
29
|
-
1. 指定需要修改的文件路径(单个或多个)
|
|
30
|
-
2. 提供一组或多组修改,每个修改包含:
|
|
31
|
-
- reason: 修改原因描述
|
|
32
|
-
- SEARCH: 需要查找的原始代码(必须包含足够上下文)
|
|
33
|
-
- REPLACE: 替换后的新代码
|
|
34
|
-
3. 工具会自动选择最适合的编辑模式
|
|
35
|
-
|
|
36
|
-
## 核心原则
|
|
37
|
-
1. **精准修改**: 只修改必要的代码部分,保持其他部分不变
|
|
38
|
-
2. **最小补丁原则**: 生成最小范围的补丁,包含必要的上下文
|
|
39
|
-
3. **唯一匹配**: 确保搜索文本在文件中唯一匹配
|
|
40
|
-
4. **格式保持**: 严格保持原始代码的格式风格
|
|
41
|
-
5. **部分成功**: 支持多个文件编辑,允许部分文件编辑成功
|
|
42
|
-
|
|
43
|
-
"""
|
|
44
|
-
parameters = {
|
|
45
|
-
"type": "object",
|
|
46
|
-
"properties": {
|
|
47
|
-
"files": {
|
|
48
|
-
"type": "array",
|
|
49
|
-
"description": "需要修改的文件路径列表",
|
|
50
|
-
"items": {
|
|
51
|
-
"type": "object",
|
|
52
|
-
"properties": {
|
|
53
|
-
"path": {"type": "string", "description": "文件路径"},
|
|
54
|
-
"changes": {
|
|
55
|
-
"type": "array",
|
|
56
|
-
"description": "一组或多组修改,每个修改必须包含1-2行上下文用于精确定位",
|
|
57
|
-
"items": {
|
|
58
|
-
"type": "object",
|
|
59
|
-
"properties": {
|
|
60
|
-
"reason": {
|
|
61
|
-
"type": "string",
|
|
62
|
-
"description": "修改的原因",
|
|
63
|
-
},
|
|
64
|
-
"SEARCH": {
|
|
65
|
-
"type": "string",
|
|
66
|
-
"description": "需要查找的原始代码",
|
|
67
|
-
},
|
|
68
|
-
"REPLACE": {
|
|
69
|
-
"type": "string",
|
|
70
|
-
"description": "替换后的新代码",
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
"required": ["path", "changes"],
|
|
77
|
-
},
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
"required": ["files"],
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
84
|
-
"""执行文件编辑操作,支持快速编辑和AI辅助编辑两种模式。
|
|
85
|
-
|
|
86
|
-
主要功能:
|
|
87
|
-
1. 处理多个文件的创建或修改,支持不存在的文件
|
|
88
|
-
2. 每个文件独立处理,允许部分文件编辑成功
|
|
89
|
-
3. 自动选择编辑模式(fast_edit或slow_edit)
|
|
90
|
-
4. 保存修改前后的文件状态以便回滚
|
|
91
|
-
5. 提供详细的执行状态输出
|
|
92
|
-
|
|
93
|
-
参数:
|
|
94
|
-
args: 包含以下键的字典:
|
|
95
|
-
- files: 文件列表,每个文件包含(必填):
|
|
96
|
-
- path: 要修改的文件路径
|
|
97
|
-
- changes: 修改列表,每个修改包含:
|
|
98
|
-
- reason: 修改原因描述
|
|
99
|
-
- SEARCH: 需要查找的原始代码(必须包含足够上下文)
|
|
100
|
-
- REPLACE: 替换后的新代码
|
|
101
|
-
|
|
102
|
-
返回:
|
|
103
|
-
Dict[str, Any] 包含:
|
|
104
|
-
- success: 是否至少有一个文件编辑成功(True/False)
|
|
105
|
-
- stdout: 成功时的输出消息
|
|
106
|
-
- stderr: 失败时的错误消息
|
|
107
|
-
- results: 每个文件的处理结果列表
|
|
108
|
-
|
|
109
|
-
异常处理:
|
|
110
|
-
1. 捕获并记录文件操作异常
|
|
111
|
-
2. 失败的修改尝试回滚到原始状态
|
|
112
|
-
3. 新创建的文件在失败时会被删除
|
|
113
|
-
4. 提供3次重试机制确保操作可靠性
|
|
114
|
-
5. 支持大文件处理(自动上传到模型平台)
|
|
115
|
-
|
|
116
|
-
实现细节:
|
|
117
|
-
1. 优先尝试fast_edit模式
|
|
118
|
-
2. 如果fast_edit失败,则尝试slow_edit模式
|
|
119
|
-
3. 严格检查搜索文本的唯一匹配性
|
|
120
|
-
4. 保持原始代码的格式风格
|
|
121
|
-
"""
|
|
122
|
-
import os
|
|
123
|
-
|
|
124
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
125
|
-
|
|
126
|
-
stdout_messages = []
|
|
127
|
-
stderr_messages = []
|
|
128
|
-
overall_success = False
|
|
129
|
-
file_results = []
|
|
130
|
-
|
|
131
|
-
for file_info in args["files"]:
|
|
132
|
-
file_path = os.path.abspath(file_info["path"])
|
|
133
|
-
changes = file_info["changes"]
|
|
134
|
-
|
|
135
|
-
# 创建已处理文件变量,用于失败时回滚
|
|
136
|
-
original_content = None
|
|
137
|
-
processed = False
|
|
138
|
-
file_success = True
|
|
139
|
-
|
|
140
|
-
try:
|
|
141
|
-
file_exists = os.path.exists(file_path)
|
|
142
|
-
content = ""
|
|
143
|
-
|
|
144
|
-
try:
|
|
145
|
-
# 如果文件存在,则读取内容
|
|
146
|
-
if file_exists:
|
|
147
|
-
with open(file_path, "r", encoding="utf-8") as f:
|
|
148
|
-
content = f.read()
|
|
149
|
-
original_content = content
|
|
150
|
-
|
|
151
|
-
print(f"⚙️ 正在处理文件 {file_path}...")
|
|
152
|
-
success, temp_content = EditFileHandler._fast_edit(
|
|
153
|
-
file_path, changes
|
|
154
|
-
)
|
|
155
|
-
if not success:
|
|
156
|
-
print(f"❌ 文件 {file_path} 处理失败")
|
|
157
|
-
file_results.append(
|
|
158
|
-
{
|
|
159
|
-
"file": file_path,
|
|
160
|
-
"success": False,
|
|
161
|
-
"stdout": "",
|
|
162
|
-
"stderr": temp_content,
|
|
163
|
-
}
|
|
164
|
-
)
|
|
165
|
-
continue
|
|
166
|
-
|
|
167
|
-
print(f"✅ 文件 {file_path} 内容生成完成")
|
|
168
|
-
|
|
169
|
-
# 只有当所有替换操作都成功时,才写回文件
|
|
170
|
-
if success and (
|
|
171
|
-
temp_content != original_content or not file_exists
|
|
172
|
-
):
|
|
173
|
-
# 确保目录存在
|
|
174
|
-
os.makedirs(
|
|
175
|
-
os.path.dirname(os.path.abspath(file_path)), exist_ok=True
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
with open(file_path, "w", encoding="utf-8") as f:
|
|
179
|
-
f.write(temp_content)
|
|
180
|
-
|
|
181
|
-
processed = True
|
|
182
|
-
|
|
183
|
-
action = "创建并写入" if not file_exists else "成功修改"
|
|
184
|
-
stdout_message = f"文件 {file_path} {action} 完成"
|
|
185
|
-
stdout_messages.append(stdout_message)
|
|
186
|
-
PrettyOutput.print(stdout_message, OutputType.SUCCESS)
|
|
187
|
-
overall_success = True
|
|
188
|
-
|
|
189
|
-
file_results.append(
|
|
190
|
-
{
|
|
191
|
-
"file": file_path,
|
|
192
|
-
"success": True,
|
|
193
|
-
"stdout": stdout_message,
|
|
194
|
-
"stderr": "",
|
|
195
|
-
}
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
except Exception as e:
|
|
199
|
-
stderr_message = f"处理文件 {file_path} 时出错: {str(e)}"
|
|
200
|
-
stderr_messages.append(stderr_message)
|
|
201
|
-
PrettyOutput.print(stderr_message, OutputType.WARNING)
|
|
202
|
-
file_success = False
|
|
203
|
-
file_results.append(
|
|
204
|
-
{
|
|
205
|
-
"file": file_path,
|
|
206
|
-
"success": False,
|
|
207
|
-
"stdout": "",
|
|
208
|
-
"stderr": stderr_message,
|
|
209
|
-
}
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
except Exception as e:
|
|
213
|
-
error_msg = f"文件搜索替换操作失败: {str(e)}"
|
|
214
|
-
PrettyOutput.print(error_msg, OutputType.WARNING)
|
|
215
|
-
|
|
216
|
-
# 如果有已修改的文件,尝试回滚
|
|
217
|
-
if processed:
|
|
218
|
-
rollback_message = "操作失败,正在回滚修改..."
|
|
219
|
-
stderr_messages.append(rollback_message)
|
|
220
|
-
PrettyOutput.print(rollback_message, OutputType.WARNING)
|
|
221
|
-
|
|
222
|
-
try:
|
|
223
|
-
if original_content is None:
|
|
224
|
-
# 如果是新创建的文件,则删除
|
|
225
|
-
if os.path.exists(file_path):
|
|
226
|
-
os.remove(file_path)
|
|
227
|
-
stderr_messages.append(f"已删除新创建的文件: {file_path}")
|
|
228
|
-
else:
|
|
229
|
-
# 如果是修改的文件,则恢复原内容
|
|
230
|
-
with open(file_path, "w", encoding="utf-8") as f:
|
|
231
|
-
f.write(original_content)
|
|
232
|
-
stderr_messages.append(f"已回滚文件: {file_path}")
|
|
233
|
-
except:
|
|
234
|
-
stderr_messages.append(f"回滚文件失败: {file_path}")
|
|
235
|
-
|
|
236
|
-
file_results.append(
|
|
237
|
-
{
|
|
238
|
-
"file": file_path,
|
|
239
|
-
"success": False,
|
|
240
|
-
"stdout": "",
|
|
241
|
-
"stderr": error_msg,
|
|
242
|
-
}
|
|
243
|
-
)
|
|
244
|
-
|
|
245
|
-
# 整合所有错误信息到stderr
|
|
246
|
-
all_stderr = []
|
|
247
|
-
for result in file_results:
|
|
248
|
-
if not result["success"]:
|
|
249
|
-
all_stderr.append(f"文件 {result['file']} 处理失败: {result['stderr']}")
|
|
250
|
-
|
|
251
|
-
return {
|
|
252
|
-
"success": overall_success,
|
|
253
|
-
"stdout": "\n".join(stdout_messages) if overall_success else "",
|
|
254
|
-
"stderr": "\n".join(all_stderr) if not overall_success else "",
|
|
255
|
-
}
|