jarvis-ai-assistant 0.1.193__py3-none-any.whl → 0.1.195__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 +45 -41
- jarvis/jarvis_agent/builtin_input_handler.py +26 -4
- jarvis/jarvis_agent/jarvis.py +30 -19
- jarvis/jarvis_agent/main.py +20 -12
- jarvis/jarvis_agent/output_handler.py +7 -7
- jarvis/jarvis_agent/shell_input_handler.py +14 -11
- jarvis/jarvis_code_agent/code_agent.py +81 -79
- jarvis/jarvis_code_agent/lint.py +92 -105
- jarvis/jarvis_code_analysis/checklists/__init__.py +1 -1
- jarvis/jarvis_code_analysis/checklists/c_cpp.py +1 -1
- jarvis/jarvis_code_analysis/checklists/csharp.py +1 -1
- jarvis/jarvis_code_analysis/checklists/data_format.py +1 -1
- jarvis/jarvis_code_analysis/checklists/devops.py +1 -1
- jarvis/jarvis_code_analysis/checklists/docs.py +1 -1
- jarvis/jarvis_code_analysis/checklists/go.py +1 -1
- jarvis/jarvis_code_analysis/checklists/infrastructure.py +1 -1
- jarvis/jarvis_code_analysis/checklists/java.py +1 -1
- jarvis/jarvis_code_analysis/checklists/javascript.py +1 -1
- jarvis/jarvis_code_analysis/checklists/kotlin.py +1 -1
- jarvis/jarvis_code_analysis/checklists/loader.py +31 -29
- jarvis/jarvis_code_analysis/checklists/php.py +1 -1
- jarvis/jarvis_code_analysis/checklists/python.py +1 -1
- jarvis/jarvis_code_analysis/checklists/ruby.py +1 -1
- jarvis/jarvis_code_analysis/checklists/rust.py +1 -1
- jarvis/jarvis_code_analysis/checklists/shell.py +1 -1
- jarvis/jarvis_code_analysis/checklists/sql.py +1 -1
- jarvis/jarvis_code_analysis/checklists/swift.py +1 -1
- jarvis/jarvis_code_analysis/checklists/web.py +1 -1
- jarvis/jarvis_code_analysis/code_review.py +292 -190
- jarvis/jarvis_dev/main.py +73 -56
- jarvis/jarvis_git_details/main.py +29 -33
- jarvis/jarvis_git_squash/main.py +13 -11
- jarvis/jarvis_git_utils/git_commiter.py +15 -5
- jarvis/jarvis_mcp/__init__.py +8 -10
- jarvis/jarvis_mcp/sse_mcp_client.py +182 -205
- jarvis/jarvis_mcp/stdio_mcp_client.py +93 -120
- jarvis/jarvis_mcp/streamable_mcp_client.py +117 -142
- jarvis/jarvis_methodology/main.py +71 -39
- jarvis/jarvis_multi_agent/__init__.py +24 -16
- jarvis/jarvis_multi_agent/main.py +10 -4
- jarvis/jarvis_platform/__init__.py +1 -1
- jarvis/jarvis_platform/base.py +44 -18
- jarvis/jarvis_platform/human.py +15 -3
- jarvis/jarvis_platform/kimi.py +117 -81
- jarvis/jarvis_platform/openai.py +23 -28
- jarvis/jarvis_platform/registry.py +43 -29
- jarvis/jarvis_platform/tongyi.py +16 -10
- jarvis/jarvis_platform/yuanbao.py +197 -144
- jarvis/jarvis_platform_manager/main.py +4 -2
- jarvis/jarvis_smart_shell/main.py +35 -30
- jarvis/jarvis_tools/ask_user.py +8 -16
- jarvis/jarvis_tools/base.py +3 -2
- jarvis/jarvis_tools/chdir.py +7 -19
- jarvis/jarvis_tools/cli/main.py +14 -10
- jarvis/jarvis_tools/code_plan.py +10 -31
- jarvis/jarvis_tools/create_code_agent.py +6 -11
- jarvis/jarvis_tools/create_sub_agent.py +10 -22
- jarvis/jarvis_tools/edit_file.py +98 -76
- jarvis/jarvis_tools/execute_script.py +46 -46
- jarvis/jarvis_tools/file_analyzer.py +22 -34
- jarvis/jarvis_tools/file_operation.py +69 -62
- jarvis/jarvis_tools/generate_new_tool.py +0 -2
- jarvis/jarvis_tools/methodology.py +19 -23
- jarvis/jarvis_tools/read_code.py +35 -35
- jarvis/jarvis_tools/read_webpage.py +7 -16
- jarvis/jarvis_tools/registry.py +63 -30
- jarvis/jarvis_tools/rewrite_file.py +26 -29
- jarvis/jarvis_tools/search_web.py +5 -8
- jarvis/jarvis_tools/virtual_tty.py +133 -122
- jarvis/jarvis_utils/__init__.py +0 -1
- jarvis/jarvis_utils/builtin_replace_map.py +9 -9
- jarvis/jarvis_utils/config.py +60 -37
- jarvis/jarvis_utils/embedding.py +24 -19
- jarvis/jarvis_utils/file_processors.py +16 -9
- jarvis/jarvis_utils/git_utils.py +157 -107
- jarvis/jarvis_utils/globals.py +1 -1
- jarvis/jarvis_utils/input.py +85 -52
- jarvis/jarvis_utils/jarvis_history.py +43 -0
- jarvis/jarvis_utils/methodology.py +31 -24
- jarvis/jarvis_utils/output.py +164 -80
- jarvis/jarvis_utils/tag.py +2 -1
- jarvis/jarvis_utils/utils.py +84 -52
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/METADATA +362 -230
- jarvis_ai_assistant-0.1.195.dist-info/RECORD +98 -0
- jarvis/jarvis_agent/file_input_handler.py +0 -112
- jarvis/jarvis_event/__init__.py +0 -0
- jarvis_ai_assistant-0.1.193.dist-info/RECORD +0 -99
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/top_level.txt +0 -0
@@ -10,10 +10,11 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
10
10
|
|
11
11
|
class StdioMcpClient(McpClient):
|
12
12
|
"""本地MCP客户端实现
|
13
|
-
|
13
|
+
|
14
14
|
参数:
|
15
15
|
config: 配置字典(command、args、env)
|
16
16
|
"""
|
17
|
+
|
17
18
|
def __init__(self, config: Dict[str, Any]):
|
18
19
|
self.config = config
|
19
20
|
self.process = None
|
@@ -25,18 +26,18 @@ class StdioMcpClient(McpClient):
|
|
25
26
|
"""启动MCP进程"""
|
26
27
|
try:
|
27
28
|
# 构建命令和参数
|
28
|
-
command = self.config.get(
|
29
|
+
command = self.config.get("command", "")
|
29
30
|
if not command:
|
30
|
-
raise ValueError(
|
31
|
+
raise ValueError("No command specified in config")
|
31
32
|
|
32
33
|
# 获取参数列表
|
33
|
-
args = self.config.get(
|
34
|
+
args = self.config.get("args", [])
|
34
35
|
if not isinstance(args, list):
|
35
36
|
args = [str(args)]
|
36
37
|
|
37
38
|
# 获取环境变量
|
38
39
|
env = os.environ.copy()
|
39
|
-
env.update(self.config.get(
|
40
|
+
env.update(self.config.get("env", {}))
|
40
41
|
|
41
42
|
# 启动进程
|
42
43
|
self.process = subprocess.Popen(
|
@@ -45,7 +46,7 @@ class StdioMcpClient(McpClient):
|
|
45
46
|
stdout=subprocess.PIPE,
|
46
47
|
stderr=subprocess.PIPE,
|
47
48
|
env=env,
|
48
|
-
text=True
|
49
|
+
text=True,
|
49
50
|
)
|
50
51
|
|
51
52
|
except Exception as e:
|
@@ -56,24 +57,26 @@ class StdioMcpClient(McpClient):
|
|
56
57
|
"""初始化MCP连接"""
|
57
58
|
try:
|
58
59
|
# 发送初始化请求
|
59
|
-
response = self._send_request(
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
60
|
+
response = self._send_request(
|
61
|
+
"initialize",
|
62
|
+
{
|
63
|
+
"processId": os.getpid(),
|
64
|
+
"clientInfo": {"name": "jarvis", "version": "1.0.0"},
|
65
|
+
"capabilities": {},
|
66
|
+
"protocolVersion": self.protocol_version,
|
64
67
|
},
|
65
|
-
|
66
|
-
'protocolVersion': self.protocol_version
|
67
|
-
})
|
68
|
+
)
|
68
69
|
|
69
70
|
# 验证服务器响应
|
70
|
-
if
|
71
|
-
raise RuntimeError(
|
71
|
+
if "result" not in response:
|
72
|
+
raise RuntimeError(
|
73
|
+
f"初始化失败: {response.get('error', 'Unknown error')}"
|
74
|
+
)
|
75
|
+
|
76
|
+
result = response["result"]
|
72
77
|
|
73
|
-
result = response['result']
|
74
|
-
|
75
78
|
# 发送initialized通知 - 使用正确的方法名格式
|
76
|
-
self._send_notification(
|
79
|
+
self._send_notification("notifications/initialized", {})
|
77
80
|
|
78
81
|
except Exception as e:
|
79
82
|
PrettyOutput.print(f"MCP初始化失败: {str(e)}", OutputType.ERROR)
|
@@ -81,28 +84,23 @@ class StdioMcpClient(McpClient):
|
|
81
84
|
|
82
85
|
def _send_request(self, method: str, params: Dict[str, Any]) -> Dict[str, Any]:
|
83
86
|
"""发送请求到MCP进程
|
84
|
-
|
87
|
+
|
85
88
|
参数:
|
86
89
|
method: 请求方法
|
87
90
|
params: 请求参数
|
88
|
-
|
91
|
+
|
89
92
|
返回:
|
90
93
|
Dict[str, Any]: 响应结果
|
91
94
|
"""
|
92
95
|
if not self.process:
|
93
|
-
raise RuntimeError(
|
96
|
+
raise RuntimeError("MCP process not started")
|
94
97
|
|
95
98
|
try:
|
96
99
|
# 构建请求
|
97
|
-
request = {
|
98
|
-
'jsonrpc': '2.0',
|
99
|
-
'method': method,
|
100
|
-
'params': params,
|
101
|
-
'id': 1
|
102
|
-
}
|
100
|
+
request = {"jsonrpc": "2.0", "method": method, "params": params, "id": 1}
|
103
101
|
|
104
102
|
# 发送请求
|
105
|
-
self.process.stdin.write(json.dumps(request) +
|
103
|
+
self.process.stdin.write(json.dumps(request) + "\n") # type: ignore
|
106
104
|
self.process.stdin.flush() # type: ignore
|
107
105
|
|
108
106
|
# 读取响应
|
@@ -115,23 +113,19 @@ class StdioMcpClient(McpClient):
|
|
115
113
|
|
116
114
|
def _send_notification(self, method: str, params: Dict[str, Any]) -> None:
|
117
115
|
"""发送通知到MCP进程(不需要响应)
|
118
|
-
|
116
|
+
|
119
117
|
参数:
|
120
118
|
method: 通知方法
|
121
119
|
params: 通知参数
|
122
120
|
"""
|
123
121
|
if not self.process:
|
124
|
-
raise RuntimeError(
|
122
|
+
raise RuntimeError("MCP process not started")
|
125
123
|
|
126
124
|
try:
|
127
125
|
# 构建通知
|
128
|
-
notification = {
|
129
|
-
'jsonrpc': '2.0',
|
130
|
-
'method': method,
|
131
|
-
'params': params
|
132
|
-
}
|
126
|
+
notification = {"jsonrpc": "2.0", "method": method, "params": params}
|
133
127
|
# 发送通知
|
134
|
-
self.process.stdin.write(json.dumps(notification) +
|
128
|
+
self.process.stdin.write(json.dumps(notification) + "\n") # type: ignore
|
135
129
|
self.process.stdin.flush() # type: ignore
|
136
130
|
|
137
131
|
except Exception as e:
|
@@ -140,7 +134,7 @@ class StdioMcpClient(McpClient):
|
|
140
134
|
|
141
135
|
def get_tool_list(self) -> List[Dict[str, Any]]:
|
142
136
|
"""获取工具列表
|
143
|
-
|
137
|
+
|
144
138
|
返回:
|
145
139
|
List[Dict[str, Any]]: 工具列表,每个工具包含以下字段:
|
146
140
|
- name: str - 工具名称
|
@@ -148,34 +142,36 @@ class StdioMcpClient(McpClient):
|
|
148
142
|
- parameters: Dict - 工具参数
|
149
143
|
"""
|
150
144
|
try:
|
151
|
-
response = self._send_request(
|
152
|
-
if
|
145
|
+
response = self._send_request("tools/list", {})
|
146
|
+
if "result" in response and "tools" in response["result"]:
|
153
147
|
# 注意这里: 响应结构是 response['result']['tools']
|
154
|
-
tools = response[
|
148
|
+
tools = response["result"]["tools"]
|
155
149
|
# 将MCP协议字段转换为内部格式
|
156
150
|
formatted_tools = []
|
157
151
|
for tool in tools:
|
158
152
|
# 从inputSchema中提取参数定义
|
159
|
-
input_schema = tool.get(
|
153
|
+
input_schema = tool.get("inputSchema", {})
|
160
154
|
parameters = {}
|
161
|
-
if
|
162
|
-
parameters = input_schema[
|
163
|
-
|
164
|
-
formatted_tools.append(
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
155
|
+
if "properties" in input_schema:
|
156
|
+
parameters = input_schema["properties"]
|
157
|
+
|
158
|
+
formatted_tools.append(
|
159
|
+
{
|
160
|
+
"name": tool.get("name", ""),
|
161
|
+
"description": tool.get("description", ""),
|
162
|
+
"parameters": parameters,
|
163
|
+
}
|
164
|
+
)
|
169
165
|
return formatted_tools
|
170
166
|
else:
|
171
167
|
error_msg = "获取工具列表失败"
|
172
|
-
if
|
168
|
+
if "error" in response:
|
173
169
|
error_msg += f": {response['error']}"
|
174
|
-
elif
|
170
|
+
elif "result" in response:
|
175
171
|
error_msg += f": 响应格式不正确 - {response['result']}"
|
176
172
|
else:
|
177
173
|
error_msg += ": 未知错误"
|
178
|
-
|
174
|
+
|
179
175
|
PrettyOutput.print(error_msg, OutputType.ERROR)
|
180
176
|
return []
|
181
177
|
except Exception as e:
|
@@ -184,11 +180,11 @@ class StdioMcpClient(McpClient):
|
|
184
180
|
|
185
181
|
def execute(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
186
182
|
"""执行工具
|
187
|
-
|
183
|
+
|
188
184
|
参数:
|
189
185
|
tool_name: 工具名称
|
190
186
|
arguments: 参数字典,包含工具执行所需的参数
|
191
|
-
|
187
|
+
|
192
188
|
返回:
|
193
189
|
Dict[str, Any]: 执行结果,包含以下字段:
|
194
190
|
- success: bool - 是否执行成功
|
@@ -196,43 +192,34 @@ class StdioMcpClient(McpClient):
|
|
196
192
|
- stderr: str - 标准错误
|
197
193
|
"""
|
198
194
|
try:
|
199
|
-
response = self._send_request(
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
result = response['result']
|
195
|
+
response = self._send_request(
|
196
|
+
"tools/call", {"name": tool_name, "arguments": arguments}
|
197
|
+
)
|
198
|
+
if "result" in response:
|
199
|
+
result = response["result"]
|
205
200
|
# 从content中提取输出信息
|
206
|
-
stdout =
|
207
|
-
stderr =
|
208
|
-
for content in result.get(
|
209
|
-
if content.get(
|
210
|
-
stdout += content.get(
|
211
|
-
elif content.get(
|
212
|
-
stderr += content.get(
|
213
|
-
|
214
|
-
return {
|
215
|
-
'success': True,
|
216
|
-
'stdout': stdout,
|
217
|
-
'stderr': stderr
|
218
|
-
}
|
201
|
+
stdout = ""
|
202
|
+
stderr = ""
|
203
|
+
for content in result.get("content", []):
|
204
|
+
if content.get("type") == "text":
|
205
|
+
stdout += content.get("text", "")
|
206
|
+
elif content.get("type") == "error":
|
207
|
+
stderr += content.get("text", "")
|
208
|
+
|
209
|
+
return {"success": True, "stdout": stdout, "stderr": stderr}
|
219
210
|
else:
|
220
211
|
return {
|
221
|
-
|
222
|
-
|
223
|
-
|
212
|
+
"success": False,
|
213
|
+
"stdout": "",
|
214
|
+
"stderr": response.get("error", "Unknown error"),
|
224
215
|
}
|
225
216
|
except Exception as e:
|
226
217
|
PrettyOutput.print(f"执行工具失败: {str(e)}", OutputType.ERROR)
|
227
|
-
return {
|
228
|
-
'success': False,
|
229
|
-
'stdout': '',
|
230
|
-
'stderr': str(e)
|
231
|
-
}
|
218
|
+
return {"success": False, "stdout": "", "stderr": str(e)}
|
232
219
|
|
233
220
|
def get_resource_list(self) -> List[Dict[str, Any]]:
|
234
221
|
"""获取资源列表
|
235
|
-
|
222
|
+
|
236
223
|
返回:
|
237
224
|
List[Dict[str, Any]]: 资源列表,每个资源包含以下字段:
|
238
225
|
- uri: str - 资源的唯一标识符
|
@@ -241,12 +228,12 @@ class StdioMcpClient(McpClient):
|
|
241
228
|
- mimeType: str - 资源的MIME类型(可选)
|
242
229
|
"""
|
243
230
|
try:
|
244
|
-
response = self._send_request(
|
245
|
-
if
|
246
|
-
return response[
|
231
|
+
response = self._send_request("resources/list", {})
|
232
|
+
if "result" in response and "resources" in response["result"]:
|
233
|
+
return response["result"]["resources"]
|
247
234
|
else:
|
248
235
|
error_msg = "获取资源列表失败"
|
249
|
-
if
|
236
|
+
if "error" in response:
|
250
237
|
error_msg += f": {response['error']}"
|
251
238
|
else:
|
252
239
|
error_msg += ": 未知错误"
|
@@ -258,10 +245,10 @@ class StdioMcpClient(McpClient):
|
|
258
245
|
|
259
246
|
def get_resource(self, uri: str) -> Dict[str, Any]:
|
260
247
|
"""获取指定资源的内容
|
261
|
-
|
248
|
+
|
262
249
|
参数:
|
263
250
|
uri: str - 资源的URI标识符
|
264
|
-
|
251
|
+
|
265
252
|
返回:
|
266
253
|
Dict[str, Any]: 执行结果,包含以下字段:
|
267
254
|
- success: bool - 是否执行成功
|
@@ -269,60 +256,46 @@ class StdioMcpClient(McpClient):
|
|
269
256
|
- stderr: str - 错误信息
|
270
257
|
"""
|
271
258
|
try:
|
272
|
-
response = self._send_request(
|
273
|
-
|
274
|
-
|
275
|
-
if 'result' in response and 'contents' in response['result']:
|
276
|
-
contents = response['result']['contents']
|
259
|
+
response = self._send_request("resources/read", {"uri": uri})
|
260
|
+
if "result" in response and "contents" in response["result"]:
|
261
|
+
contents = response["result"]["contents"]
|
277
262
|
if contents:
|
278
263
|
content = contents[0] # 获取第一个资源内容
|
279
264
|
# 根据资源类型返回内容
|
280
|
-
if
|
265
|
+
if "text" in content:
|
281
266
|
return {
|
282
|
-
|
283
|
-
|
284
|
-
|
267
|
+
"success": True,
|
268
|
+
"stdout": content["text"],
|
269
|
+
"stderr": "",
|
285
270
|
}
|
286
|
-
elif
|
271
|
+
elif "blob" in content:
|
287
272
|
return {
|
288
|
-
|
289
|
-
|
290
|
-
|
273
|
+
"success": True,
|
274
|
+
"stdout": content["blob"],
|
275
|
+
"stderr": "",
|
291
276
|
}
|
292
|
-
return {
|
293
|
-
'success': False,
|
294
|
-
'stdout': '',
|
295
|
-
'stderr': '资源内容为空'
|
296
|
-
}
|
277
|
+
return {"success": False, "stdout": "", "stderr": "资源内容为空"}
|
297
278
|
else:
|
298
279
|
error_msg = "获取资源内容失败"
|
299
|
-
if
|
280
|
+
if "error" in response:
|
300
281
|
error_msg += f": {response['error']}"
|
301
282
|
else:
|
302
283
|
error_msg += ": 未知错误"
|
303
284
|
PrettyOutput.print(error_msg, OutputType.ERROR)
|
304
|
-
return {
|
305
|
-
'success': False,
|
306
|
-
'stdout': '',
|
307
|
-
'stderr': error_msg
|
308
|
-
}
|
285
|
+
return {"success": False, "stdout": "", "stderr": error_msg}
|
309
286
|
except Exception as e:
|
310
287
|
error_msg = f"获取资源内容失败: {str(e)}"
|
311
288
|
PrettyOutput.print(error_msg, OutputType.ERROR)
|
312
|
-
return {
|
313
|
-
'success': False,
|
314
|
-
'stdout': '',
|
315
|
-
'stderr': error_msg
|
316
|
-
}
|
289
|
+
return {"success": False, "stdout": "", "stderr": error_msg}
|
317
290
|
|
318
291
|
def __del__(self):
|
319
292
|
"""清理资源"""
|
320
293
|
if self.process:
|
321
294
|
try:
|
322
295
|
# 发送退出通知 - 使用通知而非请求
|
323
|
-
self._send_notification(
|
296
|
+
self._send_notification("notifications/exit", {})
|
324
297
|
# 等待进程结束
|
325
298
|
self.process.wait(timeout=1)
|
326
299
|
except:
|
327
300
|
# 如果进程没有正常退出,强制终止
|
328
|
-
self.process.kill()
|
301
|
+
self.process.kill()
|