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
@@ -12,42 +12,45 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
12
12
 
13
13
  class StreamableMcpClient(McpClient):
14
14
  """Streamable HTTP MCP客户端实现
15
-
15
+
16
16
  参数:
17
17
  config: 配置字典,包含以下字段:
18
18
  - base_url: str - MCP服务器的基础URL
19
19
  - auth_token: str - 认证令牌(可选)
20
20
  - headers: Dict[str, str] - 额外的HTTP头(可选)
21
21
  """
22
+
22
23
  def __init__(self, config: Dict[str, Any]):
23
24
  self.config = config
24
- self.base_url = config.get('base_url', '')
25
+ self.base_url = config.get("base_url", "")
25
26
  if not self.base_url:
26
- raise ValueError('No base_url specified in config')
27
-
27
+ raise ValueError("No base_url specified in config")
28
+
28
29
  # 设置HTTP客户端
29
30
  self.session = requests.Session()
30
- self.session.headers.update({
31
- 'Content-Type': 'application/json',
32
- 'Accept': 'application/json',
33
- })
34
-
31
+ self.session.headers.update(
32
+ {
33
+ "Content-Type": "application/json",
34
+ "Accept": "application/json",
35
+ }
36
+ )
37
+
35
38
  # 添加认证令牌(如果提供)
36
- auth_token = config.get('auth_token')
39
+ auth_token = config.get("auth_token")
37
40
  if auth_token:
38
- self.session.headers['Authorization'] = f'Bearer {auth_token}'
39
-
41
+ self.session.headers["Authorization"] = f"Bearer {auth_token}"
42
+
40
43
  # 添加额外的HTTP头
41
- extra_headers = config.get('headers', {})
44
+ extra_headers = config.get("headers", {})
42
45
  self.session.headers.update(extra_headers)
43
-
46
+
44
47
  # 请求相关属性
45
48
  self.pending_requests = {} # 存储等待响应的请求 {id: Event}
46
- self.request_results = {} # 存储请求结果 {id: result}
49
+ self.request_results = {} # 存储请求结果 {id: result}
47
50
  self.notification_handlers = {}
48
51
  self.event_lock = threading.Lock()
49
52
  self.request_id_counter = 0
50
-
53
+
51
54
  # 初始化连接
52
55
  self._initialize()
53
56
 
@@ -55,22 +58,24 @@ class StreamableMcpClient(McpClient):
55
58
  """初始化MCP连接"""
56
59
  try:
57
60
  # 发送初始化请求
58
- response = self._send_request('initialize', {
59
- 'processId': None, # 远程客户端不需要进程ID
60
- 'clientInfo': {
61
- 'name': 'jarvis',
62
- 'version': '1.0.0'
61
+ response = self._send_request(
62
+ "initialize",
63
+ {
64
+ "processId": None, # 远程客户端不需要进程ID
65
+ "clientInfo": {"name": "jarvis", "version": "1.0.0"},
66
+ "capabilities": {},
67
+ "protocolVersion": "2025-03-26",
63
68
  },
64
- 'capabilities': {},
65
- 'protocolVersion': "2025-03-26"
66
- })
69
+ )
67
70
 
68
71
  # 验证服务器响应
69
- if 'result' not in response:
70
- raise RuntimeError(f"初始化失败: {response.get('error', 'Unknown error')}")
72
+ if "result" not in response:
73
+ raise RuntimeError(
74
+ f"初始化失败: {response.get('error', 'Unknown error')}"
75
+ )
71
76
 
72
77
  # 发送initialized通知
73
- self._send_notification('notifications/initialized', {})
78
+ self._send_notification("notifications/initialized", {})
74
79
 
75
80
  except Exception as e:
76
81
  PrettyOutput.print(f"MCP初始化失败: {str(e)}", OutputType.ERROR)
@@ -78,7 +83,7 @@ class StreamableMcpClient(McpClient):
78
83
 
79
84
  def register_notification_handler(self, method: str, handler: Callable) -> None:
80
85
  """注册通知处理器
81
-
86
+
82
87
  参数:
83
88
  method: 通知方法名
84
89
  handler: 处理通知的回调函数,接收params参数
@@ -90,7 +95,7 @@ class StreamableMcpClient(McpClient):
90
95
 
91
96
  def unregister_notification_handler(self, method: str, handler: Callable) -> None:
92
97
  """注销通知处理器
93
-
98
+
94
99
  参数:
95
100
  method: 通知方法名
96
101
  handler: 要注销的处理器函数
@@ -110,38 +115,36 @@ class StreamableMcpClient(McpClient):
110
115
 
111
116
  def _send_request(self, method: str, params: Dict[str, Any]) -> Dict[str, Any]:
112
117
  """发送请求到MCP服务器
113
-
118
+
114
119
  参数:
115
120
  method: 请求方法
116
121
  params: 请求参数
117
-
122
+
118
123
  返回:
119
124
  Dict[str, Any]: 响应结果
120
125
  """
121
126
  # 生成唯一请求ID
122
127
  req_id = self._get_next_request_id()
123
-
128
+
124
129
  # 创建事件标志,用于等待响应
125
130
  event = threading.Event()
126
-
131
+
127
132
  with self.event_lock:
128
133
  self.pending_requests[req_id] = event
129
-
134
+
130
135
  try:
131
136
  # 构建请求
132
137
  request = {
133
- 'jsonrpc': '2.0',
134
- 'method': method,
135
- 'params': params,
136
- 'id': req_id
138
+ "jsonrpc": "2.0",
139
+ "method": method,
140
+ "params": params,
141
+ "id": req_id,
137
142
  }
138
143
 
139
144
  # 发送请求到Streamable HTTP端点
140
- mcp_url = urljoin(self.base_url, 'mcp')
145
+ mcp_url = urljoin(self.base_url, "mcp")
141
146
  response = self.session.post(
142
- mcp_url,
143
- json=request,
144
- stream=True # 启用流式传输
147
+ mcp_url, json=request, stream=True # 启用流式传输
145
148
  )
146
149
  response.raise_for_status()
147
150
 
@@ -151,22 +154,22 @@ class StreamableMcpClient(McpClient):
151
154
  if line:
152
155
  try:
153
156
  data = json.loads(line)
154
- if 'id' in data and data['id'] == req_id:
157
+ if "id" in data and data["id"] == req_id:
155
158
  # 这是我们的请求响应
156
159
  result = data
157
160
  break
158
- elif 'method' in data:
161
+ elif "method" in data:
159
162
  # 这是一个通知
160
- method = data.get('method', '')
161
- params = data.get('params', {})
163
+ method = data.get("method", "")
164
+ params = data.get("params", {})
162
165
  if method in self.notification_handlers:
163
166
  for handler in self.notification_handlers[method]:
164
167
  try:
165
168
  handler(params)
166
169
  except Exception as e:
167
170
  PrettyOutput.print(
168
- f"处理通知时出错 ({method}): {e}",
169
- OutputType.ERROR
171
+ f"处理通知时出错 ({method}): {e}",
172
+ OutputType.ERROR,
170
173
  )
171
174
  except json.JSONDecodeError:
172
175
  PrettyOutput.print(f"无法解析响应: {line}", OutputType.WARNING)
@@ -188,25 +191,18 @@ class StreamableMcpClient(McpClient):
188
191
 
189
192
  def _send_notification(self, method: str, params: Dict[str, Any]) -> None:
190
193
  """发送通知到MCP服务器(不需要响应)
191
-
194
+
192
195
  参数:
193
196
  method: 通知方法
194
197
  params: 通知参数
195
198
  """
196
199
  try:
197
200
  # 构建通知
198
- notification = {
199
- 'jsonrpc': '2.0',
200
- 'method': method,
201
- 'params': params
202
- }
201
+ notification = {"jsonrpc": "2.0", "method": method, "params": params}
203
202
 
204
203
  # 发送通知到Streamable HTTP端点
205
- mcp_url = urljoin(self.base_url, 'mcp')
206
- response = self.session.post(
207
- mcp_url,
208
- json=notification
209
- )
204
+ mcp_url = urljoin(self.base_url, "mcp")
205
+ response = self.session.post(mcp_url, json=notification)
210
206
  response.raise_for_status()
211
207
 
212
208
  except Exception as e:
@@ -215,7 +211,7 @@ class StreamableMcpClient(McpClient):
215
211
 
216
212
  def get_tool_list(self) -> List[Dict[str, Any]]:
217
213
  """获取工具列表
218
-
214
+
219
215
  返回:
220
216
  List[Dict[str, Any]]: 工具列表,每个工具包含以下字段:
221
217
  - name: str - 工具名称
@@ -223,34 +219,36 @@ class StreamableMcpClient(McpClient):
223
219
  - parameters: Dict - 工具参数
224
220
  """
225
221
  try:
226
- response = self._send_request('tools/list', {})
227
- if 'result' in response and 'tools' in response['result']:
222
+ response = self._send_request("tools/list", {})
223
+ if "result" in response and "tools" in response["result"]:
228
224
  # 注意这里: 响应结构是 response['result']['tools']
229
- tools = response['result']['tools']
225
+ tools = response["result"]["tools"]
230
226
  # 将MCP协议字段转换为内部格式
231
227
  formatted_tools = []
232
228
  for tool in tools:
233
229
  # 从inputSchema中提取参数定义
234
- input_schema = tool.get('inputSchema', {})
230
+ input_schema = tool.get("inputSchema", {})
235
231
  parameters = {}
236
- if 'properties' in input_schema:
237
- parameters = input_schema['properties']
238
-
239
- formatted_tools.append({
240
- 'name': tool.get('name', ''),
241
- 'description': tool.get('description', ''),
242
- 'parameters': parameters
243
- })
232
+ if "properties" in input_schema:
233
+ parameters = input_schema["properties"]
234
+
235
+ formatted_tools.append(
236
+ {
237
+ "name": tool.get("name", ""),
238
+ "description": tool.get("description", ""),
239
+ "parameters": parameters,
240
+ }
241
+ )
244
242
  return formatted_tools
245
243
  else:
246
244
  error_msg = "获取工具列表失败"
247
- if 'error' in response:
245
+ if "error" in response:
248
246
  error_msg += f": {response['error']}"
249
- elif 'result' in response:
247
+ elif "result" in response:
250
248
  error_msg += f": 响应格式不正确 - {response['result']}"
251
249
  else:
252
250
  error_msg += ": 未知错误"
253
-
251
+
254
252
  PrettyOutput.print(error_msg, OutputType.ERROR)
255
253
  return []
256
254
  except Exception as e:
@@ -259,11 +257,11 @@ class StreamableMcpClient(McpClient):
259
257
 
260
258
  def execute(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
261
259
  """执行工具
262
-
260
+
263
261
  参数:
264
262
  tool_name: 工具名称
265
263
  arguments: 参数字典,包含工具执行所需的参数
266
-
264
+
267
265
  返回:
268
266
  Dict[str, Any]: 执行结果,包含以下字段:
269
267
  - success: bool - 是否执行成功
@@ -271,43 +269,34 @@ class StreamableMcpClient(McpClient):
271
269
  - stderr: str - 标准错误
272
270
  """
273
271
  try:
274
- response = self._send_request('tools/call', {
275
- 'name': tool_name,
276
- 'arguments': arguments
277
- })
278
- if 'result' in response:
279
- result = response['result']
272
+ response = self._send_request(
273
+ "tools/call", {"name": tool_name, "arguments": arguments}
274
+ )
275
+ if "result" in response:
276
+ result = response["result"]
280
277
  # 从content中提取输出信息
281
- stdout = ''
282
- stderr = ''
283
- for content in result.get('content', []):
284
- if content.get('type') == 'text':
285
- stdout += content.get('text', '')
286
- elif content.get('type') == 'error':
287
- stderr += content.get('text', '')
288
-
289
- return {
290
- 'success': True,
291
- 'stdout': stdout,
292
- 'stderr': stderr
293
- }
278
+ stdout = ""
279
+ stderr = ""
280
+ for content in result.get("content", []):
281
+ if content.get("type") == "text":
282
+ stdout += content.get("text", "")
283
+ elif content.get("type") == "error":
284
+ stderr += content.get("text", "")
285
+
286
+ return {"success": True, "stdout": stdout, "stderr": stderr}
294
287
  else:
295
288
  return {
296
- 'success': False,
297
- 'stdout': '',
298
- 'stderr': response.get('error', 'Unknown error')
289
+ "success": False,
290
+ "stdout": "",
291
+ "stderr": response.get("error", "Unknown error"),
299
292
  }
300
293
  except Exception as e:
301
294
  PrettyOutput.print(f"执行工具失败: {str(e)}", OutputType.ERROR)
302
- return {
303
- 'success': False,
304
- 'stdout': '',
305
- 'stderr': str(e)
306
- }
295
+ return {"success": False, "stdout": "", "stderr": str(e)}
307
296
 
308
297
  def get_resource_list(self) -> List[Dict[str, Any]]:
309
298
  """获取资源列表
310
-
299
+
311
300
  返回:
312
301
  List[Dict[str, Any]]: 资源列表,每个资源包含以下字段:
313
302
  - uri: str - 资源的唯一标识符
@@ -316,12 +305,12 @@ class StreamableMcpClient(McpClient):
316
305
  - mimeType: str - 资源的MIME类型(可选)
317
306
  """
318
307
  try:
319
- response = self._send_request('resources/list', {})
320
- if 'result' in response and 'resources' in response['result']:
321
- return response['result']['resources']
308
+ response = self._send_request("resources/list", {})
309
+ if "result" in response and "resources" in response["result"]:
310
+ return response["result"]["resources"]
322
311
  else:
323
312
  error_msg = "获取资源列表失败"
324
- if 'error' in response:
313
+ if "error" in response:
325
314
  error_msg += f": {response['error']}"
326
315
  else:
327
316
  error_msg += ": 未知错误"
@@ -333,10 +322,10 @@ class StreamableMcpClient(McpClient):
333
322
 
334
323
  def get_resource(self, uri: str) -> Dict[str, Any]:
335
324
  """获取指定资源的内容
336
-
325
+
337
326
  参数:
338
327
  uri: str - 资源的URI标识符
339
-
328
+
340
329
  返回:
341
330
  Dict[str, Any]: 执行结果,包含以下字段:
342
331
  - success: bool - 是否执行成功
@@ -344,51 +333,37 @@ class StreamableMcpClient(McpClient):
344
333
  - stderr: str - 错误信息
345
334
  """
346
335
  try:
347
- response = self._send_request('resources/read', {
348
- 'uri': uri
349
- })
350
- if 'result' in response and 'contents' in response['result']:
351
- contents = response['result']['contents']
336
+ response = self._send_request("resources/read", {"uri": uri})
337
+ if "result" in response and "contents" in response["result"]:
338
+ contents = response["result"]["contents"]
352
339
  if contents:
353
340
  content = contents[0] # 获取第一个资源内容
354
341
  # 根据资源类型返回内容
355
- if 'text' in content:
342
+ if "text" in content:
356
343
  return {
357
- 'success': True,
358
- 'stdout': content['text'],
359
- 'stderr': ''
344
+ "success": True,
345
+ "stdout": content["text"],
346
+ "stderr": "",
360
347
  }
361
- elif 'blob' in content:
348
+ elif "blob" in content:
362
349
  return {
363
- 'success': True,
364
- 'stdout': content['blob'],
365
- 'stderr': ''
350
+ "success": True,
351
+ "stdout": content["blob"],
352
+ "stderr": "",
366
353
  }
367
- return {
368
- 'success': False,
369
- 'stdout': '',
370
- 'stderr': '资源内容为空'
371
- }
354
+ return {"success": False, "stdout": "", "stderr": "资源内容为空"}
372
355
  else:
373
356
  error_msg = "获取资源内容失败"
374
- if 'error' in response:
357
+ if "error" in response:
375
358
  error_msg += f": {response['error']}"
376
359
  else:
377
360
  error_msg += ": 未知错误"
378
361
  PrettyOutput.print(error_msg, OutputType.ERROR)
379
- return {
380
- 'success': False,
381
- 'stdout': '',
382
- 'stderr': error_msg
383
- }
362
+ return {"success": False, "stdout": "", "stderr": error_msg}
384
363
  except Exception as e:
385
364
  error_msg = f"获取资源内容失败: {str(e)}"
386
365
  PrettyOutput.print(error_msg, OutputType.ERROR)
387
- return {
388
- 'success': False,
389
- 'stdout': '',
390
- 'stderr': error_msg
391
- }
366
+ return {"success": False, "stdout": "", "stderr": error_msg}
392
367
 
393
368
  def __del__(self):
394
369
  """清理资源"""
@@ -398,7 +373,7 @@ class StreamableMcpClient(McpClient):
398
373
  event.set() # 释放所有等待的请求
399
374
  self.pending_requests.clear()
400
375
  self.request_results.clear()
401
-
376
+
402
377
  # 关闭HTTP会话
403
378
  if self.session:
404
- self.session.close()
379
+ self.session.close()