jarvis-ai-assistant 0.2.1__py3-none-any.whl → 0.2.2__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 (30) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/jarvis.py +61 -59
  3. jarvis/jarvis_agent/main.py +42 -40
  4. jarvis/jarvis_code_agent/code_agent.py +35 -31
  5. jarvis/jarvis_code_analysis/code_review.py +73 -39
  6. jarvis/jarvis_git_squash/main.py +16 -12
  7. jarvis/jarvis_git_utils/git_commiter.py +25 -20
  8. jarvis/jarvis_methodology/main.py +34 -49
  9. jarvis/jarvis_multi_agent/main.py +28 -23
  10. jarvis/jarvis_platform/ai8.py +31 -22
  11. jarvis/jarvis_platform/kimi.py +31 -61
  12. jarvis/jarvis_platform/tongyi.py +62 -76
  13. jarvis/jarvis_platform/yuanbao.py +44 -50
  14. jarvis/jarvis_platform_manager/main.py +55 -90
  15. jarvis/jarvis_smart_shell/main.py +58 -87
  16. jarvis/jarvis_tools/cli/main.py +120 -153
  17. jarvis/jarvis_tools/registry.py +1 -7
  18. jarvis/jarvis_tools/search_web.py +12 -10
  19. jarvis/jarvis_utils/http.py +58 -79
  20. jarvis/jarvis_utils/output.py +1 -1
  21. jarvis_ai_assistant-0.2.2.dist-info/METADATA +228 -0
  22. {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.2.dist-info}/RECORD +26 -29
  23. {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.2.dist-info}/entry_points.txt +0 -2
  24. jarvis/jarvis_git_details/__init__.py +0 -0
  25. jarvis/jarvis_git_details/main.py +0 -265
  26. jarvis/jarvis_platform/oyi.py +0 -357
  27. jarvis_ai_assistant-0.2.1.dist-info/METADATA +0 -845
  28. {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.2.dist-info}/WHEEL +0 -0
  29. {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.2.dist-info}/licenses/LICENSE +0 -0
  30. {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.2.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
- import argparse
3
2
  import os
4
3
  import re
5
4
  import subprocess
@@ -7,6 +6,7 @@ import sys
7
6
  import tempfile
8
7
  from typing import Any, Dict, Optional
9
8
 
9
+ import typer
10
10
  import yaml # type: ignore
11
11
 
12
12
  from jarvis.jarvis_platform.registry import PlatformRegistry
@@ -21,6 +21,8 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
21
21
  from jarvis.jarvis_utils.tag import ct, ot
22
22
  from jarvis.jarvis_utils.utils import init_env, is_context_overflow
23
23
 
24
+ app = typer.Typer(help="Git commit tool")
25
+
24
26
 
25
27
  class GitCommitTool:
26
28
  name = "git_commit_agent"
@@ -305,34 +307,37 @@ commit信息
305
307
  os.chdir(original_dir)
306
308
 
307
309
 
308
- def main():
309
- init_env("欢迎使用 Jarvis-GitCommitTool,您的Git提交助手已准备就绪!")
310
- parser = argparse.ArgumentParser(description="Git commit tool")
311
- parser.add_argument(
312
- "--root-dir", type=str, default=".", help="Root directory of the Git repository"
313
- )
314
- parser.add_argument(
310
+ @app.command()
311
+ def cli(
312
+ root_dir: str = typer.Option(
313
+ ".", "--root-dir", help="Root directory of the Git repository"
314
+ ),
315
+ prefix: str = typer.Option(
316
+ "",
315
317
  "--prefix",
316
- type=str,
317
- default="",
318
318
  help="Prefix to prepend to commit message (separated by space)",
319
- )
320
- parser.add_argument(
319
+ ),
320
+ suffix: str = typer.Option(
321
+ "",
321
322
  "--suffix",
322
- type=str,
323
- default="",
324
323
  help="Suffix to append to commit message (separated by newline)",
325
- )
326
- args = parser.parse_args()
324
+ ),
325
+ ):
326
+ init_env("欢迎使用 Jarvis-GitCommitTool,您的Git提交助手已准备就绪!")
327
327
  tool = GitCommitTool()
328
328
  tool.execute(
329
329
  {
330
- "root_dir": args.root_dir,
331
- "prefix": args.prefix if hasattr(args, "prefix") else "",
332
- "suffix": args.suffix if hasattr(args, "suffix") else "",
330
+ "root_dir": root_dir,
331
+ "prefix": prefix,
332
+ "suffix": suffix,
333
333
  }
334
334
  )
335
335
 
336
336
 
337
+ def main():
338
+ """Application entry point"""
339
+ app()
340
+
341
+
337
342
  if __name__ == "__main__":
338
- sys.exit(main())
343
+ main()
@@ -8,11 +8,13 @@
8
8
  - 列出所有方法论
9
9
  """
10
10
 
11
- import argparse
12
11
  import hashlib
13
12
  import json
14
13
  import os
14
+ import sys
15
+ from typing import Optional
15
16
 
17
+ import typer
16
18
  import yaml # type: ignore
17
19
 
18
20
  from jarvis.jarvis_platform.registry import PlatformRegistry
@@ -22,8 +24,13 @@ from jarvis.jarvis_utils.methodology import (
22
24
  )
23
25
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
24
26
 
27
+ app = typer.Typer(help="方法论管理工具")
25
28
 
26
- def import_methodology(input_file):
29
+
30
+ @app.command("import")
31
+ def import_methodology(
32
+ input_file: str = typer.Argument(..., help="要导入的方法论文件路径")
33
+ ):
27
34
  """导入方法论文件(合并策略)"""
28
35
  try:
29
36
  # 加载现有方法论
@@ -56,9 +63,13 @@ def import_methodology(input_file):
56
63
  )
57
64
  except (json.JSONDecodeError, OSError) as e:
58
65
  PrettyOutput.print(f"导入失败: {str(e)}", OutputType.ERROR)
66
+ raise typer.Exit(code=1)
59
67
 
60
68
 
61
- def export_methodology(output_file):
69
+ @app.command("export")
70
+ def export_methodology(
71
+ output_file: str = typer.Argument(..., help="导出文件路径")
72
+ ):
62
73
  """导出当前方法论到单个文件"""
63
74
  try:
64
75
  methodologies = _load_all_methodologies()
@@ -72,8 +83,10 @@ def export_methodology(output_file):
72
83
  )
73
84
  except (OSError, TypeError) as e:
74
85
  PrettyOutput.print(f"导出失败: {str(e)}", OutputType.ERROR)
86
+ raise typer.Exit(code=1)
75
87
 
76
88
 
89
+ @app.command("list")
77
90
  def list_methodologies():
78
91
  """列出所有方法论"""
79
92
  try:
@@ -88,9 +101,13 @@ def list_methodologies():
88
101
  PrettyOutput.print(f"{i}. {problem_type}", OutputType.INFO)
89
102
  except (OSError, json.JSONDecodeError) as e:
90
103
  PrettyOutput.print(f"列出方法论失败: {str(e)}", OutputType.ERROR)
104
+ raise typer.Exit(code=1)
91
105
 
92
106
 
93
- def extract_methodology(input_file):
107
+ @app.command("extract")
108
+ def extract_methodology(
109
+ input_file: str = typer.Argument(..., help="要提取方法论的文本文件路径")
110
+ ):
94
111
  """从文本文件中提取方法论"""
95
112
  try:
96
113
  # 读取文本文件内容
@@ -135,7 +152,7 @@ def extract_methodology(input_file):
135
152
  except Exception as e:
136
153
  print("❌ 提取失败")
137
154
  PrettyOutput.print(f"提取方法论失败: {str(e)}", OutputType.ERROR)
138
- return
155
+ raise typer.Exit(code=1)
139
156
 
140
157
  # 提取YAML部分
141
158
  methodologies_start = response.find("<methodologies>") + len("<methodologies>")
@@ -145,7 +162,7 @@ def extract_methodology(input_file):
145
162
  PrettyOutput.print(
146
163
  "大模型未返回有效的<methodologies>格式", OutputType.ERROR
147
164
  )
148
- return
165
+ raise typer.Exit(code=1)
149
166
 
150
167
  yaml_content = response[methodologies_start:methodologies_end].strip()
151
168
 
@@ -157,7 +174,7 @@ def extract_methodology(input_file):
157
174
  except (yaml.YAMLError, KeyError, TypeError) as e:
158
175
  print("❌ YAML解析失败")
159
176
  PrettyOutput.print(f"YAML解析错误: {str(e)}", OutputType.ERROR)
160
- return
177
+ raise typer.Exit(code=1)
161
178
 
162
179
  if not extracted_methodologies:
163
180
  print("❌ 未提取到有效方法论")
@@ -190,9 +207,11 @@ def extract_methodology(input_file):
190
207
  )
191
208
  except Exception as e:
192
209
  PrettyOutput.print(f"提取失败: {str(e)}", OutputType.ERROR)
210
+ raise typer.Exit(code=1)
193
211
 
194
212
 
195
- def extract_methodology_from_url(url):
213
+ @app.command("extract-url")
214
+ def extract_methodology_from_url(url: str = typer.Argument(..., help="要提取方法论的URL")):
196
215
  """从URL提取方法论"""
197
216
  try:
198
217
  # 获取平台实例
@@ -234,7 +253,7 @@ def extract_methodology_from_url(url):
234
253
  except Exception as e:
235
254
  print("❌ 提取失败")
236
255
  PrettyOutput.print(f"提取方法论失败: {str(e)}", OutputType.ERROR)
237
- return
256
+ raise typer.Exit(code=1)
238
257
 
239
258
  # 提取YAML部分
240
259
  methodologies_start = response.find("<methodologies>") + len("<methodologies>")
@@ -244,7 +263,7 @@ def extract_methodology_from_url(url):
244
263
  PrettyOutput.print(
245
264
  "大模型未返回有效的<methodologies>格式", OutputType.ERROR
246
265
  )
247
- return
266
+ raise typer.Exit(code=1)
248
267
 
249
268
  yaml_content = response[methodologies_start:methodologies_end].strip()
250
269
 
@@ -256,7 +275,7 @@ def extract_methodology_from_url(url):
256
275
  except (yaml.YAMLError, KeyError, TypeError) as e:
257
276
  print("❌ YAML解析失败")
258
277
  PrettyOutput.print(f"YAML解析错误: {str(e)}", OutputType.ERROR)
259
- return
278
+ raise typer.Exit(code=1)
260
279
 
261
280
  if not extracted_methodologies:
262
281
  print("❌ 未提取到有效方法论")
@@ -289,46 +308,12 @@ def extract_methodology_from_url(url):
289
308
  )
290
309
  except Exception as e:
291
310
  PrettyOutput.print(f"从URL提取失败: {str(e)}", OutputType.ERROR)
311
+ raise typer.Exit(code=1)
292
312
 
293
313
 
294
- def main():
295
- """方法论管理工具主函数"""
296
- parser = argparse.ArgumentParser(description="方法论管理工具")
297
- subparsers = parser.add_subparsers(dest="command", required=True)
298
-
299
- # import命令
300
- import_parser = subparsers.add_parser("import", help="导入方法论文件(合并策略)")
301
- import_parser.add_argument("input_file", type=str, help="要导入的方法论文件路径")
302
-
303
- # export命令
304
- export_parser = subparsers.add_parser("export", help="导出当前方法论到单个文件")
305
- export_parser.add_argument("output_file", type=str, help="导出文件路径")
306
-
307
- # list命令
308
- subparsers.add_parser("list", help="列出所有方法论")
309
-
310
- # extract命令
311
- extract_parser = subparsers.add_parser("extract", help="从文本文件中提取方法论")
312
- extract_parser.add_argument(
313
- "input_file", type=str, help="要提取方法论的文本文件路径"
314
- )
315
-
316
- # extract-url命令
317
- extract_url_parser = subparsers.add_parser("extract-url", help="从URL提取方法论")
318
- extract_url_parser.add_argument("url", type=str, help="要提取方法论的URL")
319
-
320
- args = parser.parse_args()
321
-
322
- if args.command == "import":
323
- import_methodology(args.input_file)
324
- elif args.command == "export":
325
- export_methodology(args.output_file)
326
- elif args.command == "list":
327
- list_methodologies()
328
- elif args.command == "extract":
329
- extract_methodology(args.input_file)
330
- elif args.command == "extract-url":
331
- extract_methodology_from_url(args.url)
314
+ def main() -> None:
315
+ """Application entry point"""
316
+ app()
332
317
 
333
318
 
334
319
  if __name__ == "__main__":
@@ -1,27 +1,26 @@
1
1
  # -*- coding: utf-8 -*-
2
+ from typing import Optional
3
+
4
+ import typer
2
5
  import yaml
3
6
 
4
7
  from jarvis.jarvis_multi_agent import MultiAgent
5
8
  from jarvis.jarvis_utils.input import get_multiline_input
6
9
  from jarvis.jarvis_utils.utils import init_env
7
10
 
11
+ app = typer.Typer(help="多智能体系统启动器")
8
12
 
9
- def main():
10
- """从YAML配置文件初始化并运行多智能体系统
11
13
 
12
- Returns:
13
- 最终处理结果
14
- """
14
+ @app.command()
15
+ def cli(
16
+ config: str = typer.Option(..., "--config", "-c", help="YAML配置文件路径"),
17
+ user_input: Optional[str] = typer.Option(None, "--input", "-i", help="用户输入(可选)"),
18
+ ):
19
+ """从YAML配置文件初始化并运行多智能体系统"""
15
20
  init_env("欢迎使用 Jarvis-MultiAgent,您的多智能体系统已准备就绪!")
16
- import argparse
17
-
18
- parser = argparse.ArgumentParser(description="多智能体系统启动器")
19
- parser.add_argument("--config", "-c", required=True, help="YAML配置文件路径")
20
- parser.add_argument("--input", "-i", help="用户输入(可选)")
21
- args = parser.parse_args()
22
21
 
23
22
  try:
24
- with open(args.config, "r", errors="ignore") as f:
23
+ with open(config, "r", errors="ignore") as f:
25
24
  config_data = yaml.safe_load(f)
26
25
 
27
26
  # 获取agents配置
@@ -33,20 +32,26 @@ def main():
33
32
 
34
33
  # 创建并运行多智能体系统
35
34
  multi_agent = MultiAgent(agents_config, main_agent_name)
36
- user_input = (
37
- args.input
38
- if args.input is not None
35
+ final_input = (
36
+ user_input
37
+ if user_input is not None
39
38
  else get_multiline_input("请输入内容(输入空行结束):")
40
39
  )
41
- if user_input == "":
42
- return
43
- return multi_agent.run(user_input)
40
+ if not final_input:
41
+ raise typer.Exit(code=0)
42
+ multi_agent.run(final_input)
43
+
44
+ except typer.Exit:
45
+ raise
46
+ except (ValueError, RuntimeError, yaml.YAMLError) as e:
47
+ PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
48
+ raise typer.Exit(code=1)
49
+
44
50
 
45
- except yaml.YAMLError as e:
46
- raise ValueError(f"YAML配置文件解析错误: {str(e)}")
47
- except Exception as e:
48
- raise RuntimeError(f"多智能体系统初始化失败: {str(e)}")
51
+ def main() -> None:
52
+ """Application entry point."""
53
+ app()
49
54
 
50
55
 
51
56
  if __name__ == "__main__":
52
- result = main()
57
+ main()
@@ -32,15 +32,21 @@ class AI8Model(BasePlatform):
32
32
 
33
33
  self.headers = {
34
34
  "Authorization": self.token,
35
+ "sec-ch-ua-platform": '"Windows"',
36
+ "sec-ch-ua": '"Not)A;Brand";v="8", "Chromium";v="138", "Google Chrome";v="138"',
37
+ "sec-ch-ua-mobile": "?0",
35
38
  "Content-Type": "application/json",
36
39
  "Accept": "application/json, text/plain, */*",
37
- "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",
38
- "X-APP-VERSION": "2.3.0",
40
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
41
+ "X-APP-VERSION": "2.4.2",
39
42
  "Origin": self.BASE_URL,
40
43
  "Referer": f"{self.BASE_URL}/chat?_userMenuKey=chat",
41
44
  "Sec-Fetch-Site": "same-origin",
42
45
  "Sec-Fetch-Mode": "cors",
43
46
  "Sec-Fetch-Dest": "empty",
47
+ "Accept-Language": "zh-CN,zh;q=0.9",
48
+ "Accept-Encoding": "gzip, deflate, br, zstd",
49
+ "Connection": "keep-alive",
44
50
  }
45
51
 
46
52
  self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
@@ -60,7 +66,14 @@ class AI8Model(BasePlatform):
60
66
  # 1. 创建会话
61
67
  response = while_success(
62
68
  lambda: http.post(
63
- f"{self.BASE_URL}/api/chat/session", headers=self.headers, json={}
69
+ f"{self.BASE_URL}/api/chat/session",
70
+ headers=self.headers,
71
+ json={
72
+ "mcp": [],
73
+ "model": self.model_name,
74
+ "plugins": [],
75
+ "rags": [],
76
+ },
64
77
  ),
65
78
  sleep_time=5,
66
79
  )
@@ -83,6 +96,7 @@ class AI8Model(BasePlatform):
83
96
  "plugins": [],
84
97
  "localPlugins": None,
85
98
  "useAppId": 0,
99
+ "temperature": 0,
86
100
  }
87
101
 
88
102
  response = while_success(
@@ -127,33 +141,30 @@ class AI8Model(BasePlatform):
127
141
  "files": [],
128
142
  }
129
143
 
144
+ # 为流式请求构造专用的请求头,避免 'Accept' 和 'accept' 键冲突
145
+ stream_headers = self.headers.copy()
146
+ stream_headers["Accept"] = "text/event-stream" # 添加流式专用的accept头
147
+
130
148
  # 使用stream_post进行流式请求
131
149
  response_stream = while_success(
132
150
  lambda: http.stream_post(
133
151
  f"{self.BASE_URL}/api/chat/completions",
134
- headers=self.headers,
152
+ headers=stream_headers,
135
153
  json=payload,
136
154
  ),
137
155
  sleep_time=5,
138
156
  )
139
157
 
140
158
  # 处理流式响应
141
- for chunk in response_stream:
142
- if chunk:
159
+ for line in response_stream:
160
+ if line and line.startswith("data: "):
143
161
  try:
144
- line = chunk.decode("utf-8")
145
- if line.startswith("data: "):
146
- try:
147
- data = json.loads(line[6:])
148
- if data.get("type") == "string":
149
- chunk_data = data.get("data", "")
150
- if chunk_data:
151
- yield chunk_data
152
-
153
- except json.JSONDecodeError:
154
- continue
155
-
156
- except UnicodeDecodeError:
162
+ data = json.loads(line[6:])
163
+ if data.get("type") == "string":
164
+ chunk_data = data.get("data", "")
165
+ if chunk_data:
166
+ yield chunk_data
167
+ except json.JSONDecodeError:
157
168
  continue
158
169
 
159
170
  return None
@@ -239,9 +250,7 @@ class AI8Model(BasePlatform):
239
250
  PrettyOutput.print(f"会话文件未找到: {file_path}", OutputType.ERROR)
240
251
  return False
241
252
  except KeyError as e:
242
- PrettyOutput.print(
243
- f"恢复失败: 会话文件格式不正确,缺少键 {e}", OutputType.ERROR
244
- )
253
+ PrettyOutput.print(f"恢复失败: 会话文件格式不正确,缺少键 {e}", OutputType.ERROR)
245
254
  return False
246
255
  except Exception as e:
247
256
  PrettyOutput.print(f"恢复会话失败: {str(e)}", OutputType.ERROR)
@@ -156,39 +156,24 @@ class KimiModel(BasePlatform):
156
156
  sleep_time=5,
157
157
  )
158
158
 
159
- response_data = b""
160
-
161
159
  # 处理流式响应
162
- for chunk in response_stream:
163
- response_data += chunk
164
-
165
- # 尝试解析SSE格式的数据
166
- try:
167
- # 查找完整的数据行
168
- lines = response_data.decode("utf-8").split("\n")
169
- response_data = b"" # 重置缓冲区
170
-
171
- for line in lines:
172
- if not line.strip():
173
- continue
174
-
175
- # SSE格式的行通常以"data: "开头
176
- if line.startswith("data: "):
177
- try:
178
- data = json.loads(line[6:])
179
- if data.get("event") == "resp":
180
- status = data.get("file_info", {}).get("status")
181
- if status == "parsed":
182
- return True
183
- elif status == "failed":
184
- return False
185
- except json.JSONDecodeError:
186
- continue
187
-
188
- except UnicodeDecodeError:
189
- # 如果解码失败,继续累积数据
160
+ for line in response_stream:
161
+ if not line.strip():
190
162
  continue
191
163
 
164
+ # SSE格式的行通常以"data: "开头
165
+ if line.startswith("data: "):
166
+ try:
167
+ data = json.loads(line[6:])
168
+ if data.get("event") == "resp":
169
+ status = data.get("file_info", {}).get("status")
170
+ if status == "parsed":
171
+ return True
172
+ elif status == "failed":
173
+ return False
174
+ except json.JSONDecodeError:
175
+ continue
176
+
192
177
  retry_count += 1
193
178
  time.sleep(1)
194
179
 
@@ -299,40 +284,25 @@ class KimiModel(BasePlatform):
299
284
  sleep_time=5,
300
285
  )
301
286
 
302
- response_data = b""
303
-
304
287
  # 处理流式响应
305
- for chunk in response_stream:
306
- response_data += chunk
307
-
308
- # 尝试解析SSE格式的数据
309
- try:
310
- # 查找完整的数据行
311
- lines = response_data.decode("utf-8").split("\n")
312
- response_data = b"" # 重置缓冲区
313
-
314
- for line in lines:
315
- if not line.strip():
316
- continue
317
-
318
- # SSE格式的行通常以"data: "开头
319
- if line.startswith("data: "):
320
- try:
321
- data = json.loads(line[6:])
322
- event = data.get("event")
323
-
324
- if event == "cmpl":
325
- # 处理补全文本
326
- text = data.get("text", "")
327
- if text:
328
- yield text
329
- except json.JSONDecodeError:
330
- continue
331
-
332
- except UnicodeDecodeError:
333
- # 如果解码失败,继续累积数据
288
+ for line in response_stream:
289
+ if not line.strip():
334
290
  continue
335
291
 
292
+ # SSE格式的行通常以"data: "开头
293
+ if line.startswith("data: "):
294
+ try:
295
+ data = json.loads(line[6:])
296
+ event = data.get("event")
297
+
298
+ if event == "cmpl":
299
+ # 处理补全文本
300
+ text = data.get("text", "")
301
+ if text:
302
+ yield text
303
+ except json.JSONDecodeError:
304
+ continue
305
+
336
306
  return None
337
307
 
338
308
  except Exception as e: