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.
Files changed (92) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +45 -41
  3. jarvis/jarvis_agent/builtin_input_handler.py +26 -4
  4. jarvis/jarvis_agent/jarvis.py +30 -19
  5. jarvis/jarvis_agent/main.py +20 -12
  6. jarvis/jarvis_agent/output_handler.py +7 -7
  7. jarvis/jarvis_agent/shell_input_handler.py +14 -11
  8. jarvis/jarvis_code_agent/code_agent.py +81 -79
  9. jarvis/jarvis_code_agent/lint.py +92 -105
  10. jarvis/jarvis_code_analysis/checklists/__init__.py +1 -1
  11. jarvis/jarvis_code_analysis/checklists/c_cpp.py +1 -1
  12. jarvis/jarvis_code_analysis/checklists/csharp.py +1 -1
  13. jarvis/jarvis_code_analysis/checklists/data_format.py +1 -1
  14. jarvis/jarvis_code_analysis/checklists/devops.py +1 -1
  15. jarvis/jarvis_code_analysis/checklists/docs.py +1 -1
  16. jarvis/jarvis_code_analysis/checklists/go.py +1 -1
  17. jarvis/jarvis_code_analysis/checklists/infrastructure.py +1 -1
  18. jarvis/jarvis_code_analysis/checklists/java.py +1 -1
  19. jarvis/jarvis_code_analysis/checklists/javascript.py +1 -1
  20. jarvis/jarvis_code_analysis/checklists/kotlin.py +1 -1
  21. jarvis/jarvis_code_analysis/checklists/loader.py +31 -29
  22. jarvis/jarvis_code_analysis/checklists/php.py +1 -1
  23. jarvis/jarvis_code_analysis/checklists/python.py +1 -1
  24. jarvis/jarvis_code_analysis/checklists/ruby.py +1 -1
  25. jarvis/jarvis_code_analysis/checklists/rust.py +1 -1
  26. jarvis/jarvis_code_analysis/checklists/shell.py +1 -1
  27. jarvis/jarvis_code_analysis/checklists/sql.py +1 -1
  28. jarvis/jarvis_code_analysis/checklists/swift.py +1 -1
  29. jarvis/jarvis_code_analysis/checklists/web.py +1 -1
  30. jarvis/jarvis_code_analysis/code_review.py +292 -190
  31. jarvis/jarvis_dev/main.py +73 -56
  32. jarvis/jarvis_git_details/main.py +29 -33
  33. jarvis/jarvis_git_squash/main.py +13 -11
  34. jarvis/jarvis_git_utils/git_commiter.py +15 -5
  35. jarvis/jarvis_mcp/__init__.py +8 -10
  36. jarvis/jarvis_mcp/sse_mcp_client.py +182 -205
  37. jarvis/jarvis_mcp/stdio_mcp_client.py +93 -120
  38. jarvis/jarvis_mcp/streamable_mcp_client.py +117 -142
  39. jarvis/jarvis_methodology/main.py +71 -39
  40. jarvis/jarvis_multi_agent/__init__.py +24 -16
  41. jarvis/jarvis_multi_agent/main.py +10 -4
  42. jarvis/jarvis_platform/__init__.py +1 -1
  43. jarvis/jarvis_platform/base.py +44 -18
  44. jarvis/jarvis_platform/human.py +15 -3
  45. jarvis/jarvis_platform/kimi.py +117 -81
  46. jarvis/jarvis_platform/openai.py +23 -28
  47. jarvis/jarvis_platform/registry.py +43 -29
  48. jarvis/jarvis_platform/tongyi.py +16 -10
  49. jarvis/jarvis_platform/yuanbao.py +197 -144
  50. jarvis/jarvis_platform_manager/main.py +4 -2
  51. jarvis/jarvis_smart_shell/main.py +35 -30
  52. jarvis/jarvis_tools/ask_user.py +8 -16
  53. jarvis/jarvis_tools/base.py +3 -2
  54. jarvis/jarvis_tools/chdir.py +7 -19
  55. jarvis/jarvis_tools/cli/main.py +14 -10
  56. jarvis/jarvis_tools/code_plan.py +10 -31
  57. jarvis/jarvis_tools/create_code_agent.py +6 -11
  58. jarvis/jarvis_tools/create_sub_agent.py +10 -22
  59. jarvis/jarvis_tools/edit_file.py +98 -76
  60. jarvis/jarvis_tools/execute_script.py +46 -46
  61. jarvis/jarvis_tools/file_analyzer.py +22 -34
  62. jarvis/jarvis_tools/file_operation.py +69 -62
  63. jarvis/jarvis_tools/generate_new_tool.py +0 -2
  64. jarvis/jarvis_tools/methodology.py +19 -23
  65. jarvis/jarvis_tools/read_code.py +35 -35
  66. jarvis/jarvis_tools/read_webpage.py +7 -16
  67. jarvis/jarvis_tools/registry.py +63 -30
  68. jarvis/jarvis_tools/rewrite_file.py +26 -29
  69. jarvis/jarvis_tools/search_web.py +5 -8
  70. jarvis/jarvis_tools/virtual_tty.py +133 -122
  71. jarvis/jarvis_utils/__init__.py +0 -1
  72. jarvis/jarvis_utils/builtin_replace_map.py +9 -9
  73. jarvis/jarvis_utils/config.py +60 -37
  74. jarvis/jarvis_utils/embedding.py +24 -19
  75. jarvis/jarvis_utils/file_processors.py +16 -9
  76. jarvis/jarvis_utils/git_utils.py +157 -107
  77. jarvis/jarvis_utils/globals.py +1 -1
  78. jarvis/jarvis_utils/input.py +85 -52
  79. jarvis/jarvis_utils/jarvis_history.py +43 -0
  80. jarvis/jarvis_utils/methodology.py +31 -24
  81. jarvis/jarvis_utils/output.py +164 -80
  82. jarvis/jarvis_utils/tag.py +2 -1
  83. jarvis/jarvis_utils/utils.py +84 -52
  84. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/METADATA +362 -230
  85. jarvis_ai_assistant-0.1.195.dist-info/RECORD +98 -0
  86. jarvis/jarvis_agent/file_input_handler.py +0 -112
  87. jarvis/jarvis_event/__init__.py +0 -0
  88. jarvis_ai_assistant-0.1.193.dist-info/RECORD +0 -99
  89. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/WHEEL +0 -0
  90. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/entry_points.txt +0 -0
  91. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/licenses/LICENSE +0 -0
  92. {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('command', '')
29
+ command = self.config.get("command", "")
29
30
  if not command:
30
- raise ValueError('No command specified in config')
31
+ raise ValueError("No command specified in config")
31
32
 
32
33
  # 获取参数列表
33
- args = self.config.get('args', [])
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('env', {}))
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('initialize', {
60
- 'processId': os.getpid(),
61
- 'clientInfo': {
62
- 'name': 'jarvis',
63
- 'version': '1.0.0'
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
- 'capabilities': {},
66
- 'protocolVersion': self.protocol_version
67
- })
68
+ )
68
69
 
69
70
  # 验证服务器响应
70
- if 'result' not in response:
71
- raise RuntimeError(f"初始化失败: {response.get('error', 'Unknown error')}")
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('notifications/initialized', {})
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('MCP process not started')
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) + '\n') # type: ignore
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('MCP process not started')
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) + '\n') # type: ignore
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('tools/list', {})
152
- if 'result' in response and 'tools' in response['result']:
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['result']['tools']
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('inputSchema', {})
153
+ input_schema = tool.get("inputSchema", {})
160
154
  parameters = {}
161
- if 'properties' in input_schema:
162
- parameters = input_schema['properties']
163
-
164
- formatted_tools.append({
165
- 'name': tool.get('name', ''),
166
- 'description': tool.get('description', ''),
167
- 'parameters': parameters
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 'error' in response:
168
+ if "error" in response:
173
169
  error_msg += f": {response['error']}"
174
- elif 'result' in response:
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('tools/call', {
200
- 'name': tool_name,
201
- 'arguments': arguments
202
- })
203
- if 'result' in response:
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('content', []):
209
- if content.get('type') == 'text':
210
- stdout += content.get('text', '')
211
- elif content.get('type') == 'error':
212
- stderr += content.get('text', '')
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
- 'success': False,
222
- 'stdout': '',
223
- 'stderr': response.get('error', 'Unknown error')
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('resources/list', {})
245
- if 'result' in response and 'resources' in response['result']:
246
- return response['result']['resources']
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 'error' in response:
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('resources/read', {
273
- 'uri': uri
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 'text' in content:
265
+ if "text" in content:
281
266
  return {
282
- 'success': True,
283
- 'stdout': content['text'],
284
- 'stderr': ''
267
+ "success": True,
268
+ "stdout": content["text"],
269
+ "stderr": "",
285
270
  }
286
- elif 'blob' in content:
271
+ elif "blob" in content:
287
272
  return {
288
- 'success': True,
289
- 'stdout': content['blob'],
290
- 'stderr': ''
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 'error' in response:
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('notifications/exit', {})
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()