jarvis-ai-assistant 0.1.111__py3-none-any.whl → 0.1.113__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.

Potentially problematic release.


This version of jarvis-ai-assistant might be problematic. Click here for more details.

Files changed (46) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/agent.py +72 -41
  3. jarvis/jarvis_code_agent/code_agent.py +23 -5
  4. jarvis/jarvis_code_agent/file_select.py +16 -16
  5. jarvis/jarvis_code_agent/patch.py +17 -11
  6. jarvis/jarvis_code_agent/relevant_files.py +33 -40
  7. jarvis/jarvis_codebase/main.py +57 -48
  8. jarvis/jarvis_lsp/cpp.py +1 -1
  9. jarvis/jarvis_lsp/go.py +1 -1
  10. jarvis/jarvis_lsp/python.py +0 -2
  11. jarvis/jarvis_lsp/registry.py +13 -13
  12. jarvis/jarvis_lsp/rust.py +1 -1
  13. jarvis/jarvis_platform/ai8.py +14 -14
  14. jarvis/jarvis_platform/base.py +1 -1
  15. jarvis/jarvis_platform/kimi.py +17 -17
  16. jarvis/jarvis_platform/ollama.py +14 -14
  17. jarvis/jarvis_platform/openai.py +8 -8
  18. jarvis/jarvis_platform/oyi.py +19 -19
  19. jarvis/jarvis_platform/registry.py +6 -6
  20. jarvis/jarvis_platform_manager/main.py +17 -17
  21. jarvis/jarvis_rag/main.py +25 -25
  22. jarvis/jarvis_smart_shell/main.py +6 -6
  23. jarvis/jarvis_tools/ask_codebase.py +3 -3
  24. jarvis/jarvis_tools/ask_user.py +2 -2
  25. jarvis/jarvis_tools/create_code_agent.py +8 -8
  26. jarvis/jarvis_tools/create_sub_agent.py +2 -2
  27. jarvis/jarvis_tools/execute_shell.py +2 -2
  28. jarvis/jarvis_tools/file_operation.py +1 -1
  29. jarvis/jarvis_tools/git_commiter.py +8 -5
  30. jarvis/jarvis_tools/methodology.py +3 -3
  31. jarvis/jarvis_tools/rag.py +3 -3
  32. jarvis/jarvis_tools/read_code.py +1 -1
  33. jarvis/jarvis_tools/read_webpage.py +19 -6
  34. jarvis/jarvis_tools/registry.py +11 -11
  35. jarvis/jarvis_tools/search.py +88 -27
  36. jarvis/jarvis_tools/select_code_files.py +1 -1
  37. jarvis/jarvis_tools/tool_generator.py +182 -0
  38. jarvis/utils.py +69 -28
  39. jarvis_ai_assistant-0.1.113.dist-info/METADATA +460 -0
  40. jarvis_ai_assistant-0.1.113.dist-info/RECORD +64 -0
  41. jarvis_ai_assistant-0.1.111.dist-info/METADATA +0 -461
  42. jarvis_ai_assistant-0.1.111.dist-info/RECORD +0 -63
  43. {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.113.dist-info}/LICENSE +0 -0
  44. {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.113.dist-info}/WHEEL +0 -0
  45. {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.113.dist-info}/entry_points.txt +0 -0
  46. {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.113.dist-info}/top_level.txt +0 -0
jarvis/jarvis_rag/main.py CHANGED
@@ -154,9 +154,9 @@ class RAGTool:
154
154
  try:
155
155
  self.embedding_model = load_embedding_model()
156
156
  self.vector_dim = self.embedding_model.get_sentence_embedding_dimension()
157
- PrettyOutput.print("Model loaded", output_type=OutputType.SUCCESS)
157
+ PrettyOutput.print("模型加载完成", output_type=OutputType.SUCCESS)
158
158
  except Exception as e:
159
- PrettyOutput.print(f"Failed to load model: {str(e)}", output_type=OutputType.ERROR)
159
+ PrettyOutput.print(f"加载模型失败: {str(e)}", output_type=OutputType.ERROR)
160
160
  raise
161
161
 
162
162
  # 修改缓存相关初始化
@@ -218,7 +218,7 @@ class RAGTool:
218
218
  file_cache = pickle.load(f)
219
219
  self.documents.extend(file_cache["documents"])
220
220
  except Exception as e:
221
- PrettyOutput.print(f"Failed to load cache for {file_path}: {str(e)}",
221
+ PrettyOutput.print(f"加载缓存失败,文件路径:{file_path}: {str(e)}",
222
222
  output_type=OutputType.WARNING)
223
223
 
224
224
  # 重建向量索引
@@ -238,11 +238,11 @@ class RAGTool:
238
238
  vectors = np.vstack(vectors)
239
239
  self._build_index(vectors)
240
240
 
241
- PrettyOutput.print(f"Loaded {len(self.documents)} document fragments",
241
+ PrettyOutput.print(f"加载 {len(self.documents)} 个文档片段",
242
242
  output_type=OutputType.INFO)
243
243
 
244
244
  except Exception as e:
245
- PrettyOutput.print(f"Failed to load cache index: {str(e)}",
245
+ PrettyOutput.print(f"加载缓存索引失败: {str(e)}",
246
246
  output_type=OutputType.WARNING)
247
247
  self.documents = []
248
248
  self.index = None
@@ -276,7 +276,7 @@ class RAGTool:
276
276
  pickle.dump(index_data, f)
277
277
 
278
278
  except Exception as e:
279
- PrettyOutput.print(f"Failed to save cache: {str(e)}", output_type=OutputType.ERROR)
279
+ PrettyOutput.print(f"保存缓存失败: {str(e)}", output_type=OutputType.ERROR)
280
280
 
281
281
  def _build_index(self, vectors: np.ndarray):
282
282
  """Build FAISS index"""
@@ -382,7 +382,7 @@ class RAGTool:
382
382
 
383
383
  return get_embedding_batch(self.embedding_model, texts)
384
384
  except Exception as e:
385
- PrettyOutput.print(f"Batch processing failed: {str(e)}", OutputType.ERROR)
385
+ PrettyOutput.print(f"批量处理失败: {str(e)}", OutputType.ERROR)
386
386
  return np.zeros((0, self.vector_dim), dtype=np.float32) # type: ignore
387
387
 
388
388
  def _process_file(self, file_path: str) -> List[Document]:
@@ -436,7 +436,7 @@ class RAGTool:
436
436
  return documents
437
437
 
438
438
  except Exception as e:
439
- PrettyOutput.print(f"Failed to process file {file_path}: {str(e)}",
439
+ PrettyOutput.print(f"处理文件失败: {file_path}: {str(e)}",
440
440
  output_type=OutputType.ERROR)
441
441
  return []
442
442
 
@@ -517,7 +517,7 @@ class RAGTool:
517
517
  new_vectors.append(file_vectors)
518
518
 
519
519
  except Exception as e:
520
- PrettyOutput.print(f"Failed to process {file_path}: {str(e)}", OutputType.ERROR)
520
+ PrettyOutput.print(f"处理文件失败: {file_path}: {str(e)}", OutputType.ERROR)
521
521
 
522
522
  pbar.update(1)
523
523
 
@@ -542,9 +542,9 @@ class RAGTool:
542
542
  self._build_index(final_vectors)
543
543
 
544
544
  PrettyOutput.print(
545
- f"Indexed {len(self.documents)} documents "
546
- f"(New/Modified: {len(new_documents)}, "
547
- f"Unchanged: {len(unchanged_documents)})",
545
+ f"索引 {len(self.documents)} 个文档 "
546
+ f"(新/修改: {len(new_documents)}, "
547
+ f"不变: {len(unchanged_documents)})",
548
548
  OutputType.SUCCESS
549
549
  )
550
550
 
@@ -566,13 +566,13 @@ class RAGTool:
566
566
  return np.vstack(unchanged_vectors) if unchanged_vectors else None
567
567
 
568
568
  except Exception as e:
569
- PrettyOutput.print(f"Failed to get unchanged vectors: {str(e)}", OutputType.ERROR)
569
+ PrettyOutput.print(f"获取不变向量失败: {str(e)}", OutputType.ERROR)
570
570
  return None
571
571
 
572
572
  def search(self, query: str, top_k: int = 30) -> List[Tuple[Document, float]]:
573
573
  """Search documents with context window"""
574
574
  if not self.index:
575
- PrettyOutput.print("Index not built, building...", output_type=OutputType.INFO)
575
+ PrettyOutput.print("索引未构建,正在构建...", output_type=OutputType.INFO)
576
576
  self.build_index(self.root_dir)
577
577
 
578
578
  # Get query vector
@@ -670,7 +670,7 @@ Relevant documents (ordered by relevance):
670
670
  prompt += "3. Reference the documents in the answer.\n"
671
671
  if current_count + get_context_token_count(doc_content) > available_count:
672
672
  PrettyOutput.print(
673
- "Due to context length limit, some fragments were omitted",
673
+ "由于上下文长度限制,部分内容被省略",
674
674
  output_type=OutputType.WARNING
675
675
  )
676
676
  break
@@ -687,7 +687,7 @@ Relevant documents (ordered by relevance):
687
687
  return response
688
688
 
689
689
  except Exception as e:
690
- PrettyOutput.print(f"Failed to answer: {str(e)}", OutputType.ERROR)
690
+ PrettyOutput.print(f"回答失败:{str(e)}", OutputType.ERROR)
691
691
  return None
692
692
 
693
693
  def is_index_built(self) -> bool:
@@ -724,7 +724,7 @@ def main():
724
724
  args.dir = current_dir
725
725
 
726
726
  if args.dir and args.build:
727
- PrettyOutput.print(f"Processing directory: {args.dir}", output_type=OutputType.INFO)
727
+ PrettyOutput.print(f"正在处理目录: {args.dir}", output_type=OutputType.INFO)
728
728
  rag.build_index(args.dir)
729
729
  return 0
730
730
 
@@ -733,13 +733,13 @@ def main():
733
733
  if args.search:
734
734
  results = rag.query(args.search)
735
735
  if not results:
736
- PrettyOutput.print("No related content found", output_type=OutputType.WARNING)
736
+ PrettyOutput.print("未找到相关内容", output_type=OutputType.WARNING)
737
737
  return 1
738
738
 
739
739
  for doc in results:
740
- output = f"""File: {doc.metadata['file_path']}\n"""
741
- output += f"""Fragment {doc.metadata['chunk_index'] + 1}/{doc.metadata['total_chunks']}\n"""
742
- output += f"""Content:\n{doc.content}\n"""
740
+ output = f"""文件: {doc.metadata['file_path']}\n"""
741
+ output += f"""片段 {doc.metadata['chunk_index'] + 1}/{doc.metadata['total_chunks']}\n"""
742
+ output += f"""内容:\n{doc.content}\n"""
743
743
  PrettyOutput.print(output, output_type=OutputType.INFO, lang="markdown")
744
744
  return 0
745
745
 
@@ -747,19 +747,19 @@ def main():
747
747
  # Call ask method
748
748
  response = rag.ask(args.ask)
749
749
  if not response:
750
- PrettyOutput.print("Failed to get answer", output_type=OutputType.WARNING)
750
+ PrettyOutput.print("获取答案失败", output_type=OutputType.WARNING)
751
751
  return 1
752
752
 
753
753
  # Display answer
754
- output = f"""Answer:\n{response}"""
754
+ output = f"""答案:\n{response}"""
755
755
  PrettyOutput.print(output, output_type=OutputType.INFO)
756
756
  return 0
757
757
 
758
- PrettyOutput.print("Please specify operation parameters. Use -h to view help.", output_type=OutputType.WARNING)
758
+ PrettyOutput.print("请指定操作参数。使用 -h 查看帮助。", output_type=OutputType.WARNING)
759
759
  return 1
760
760
 
761
761
  except Exception as e:
762
- PrettyOutput.print(f"Failed to execute: {str(e)}", output_type=OutputType.ERROR)
762
+ PrettyOutput.print(f"执行失败: {str(e)}", output_type=OutputType.ERROR)
763
763
  return 1
764
764
 
765
765
  if __name__ == "__main__":
@@ -13,7 +13,7 @@ from jarvis.utils import PrettyOutput, OutputType, get_shell_name, init_env
13
13
  def execute_command(command: str) -> None:
14
14
  """Show command and allow user to edit, then execute, Ctrl+C to cancel"""
15
15
  try:
16
- print("Generated command (can be edited, press Enter to execute, Ctrl+C to cancel):")
16
+ print("生成的命令 (可以编辑, 按回车执行, Ctrl+C 取消):")
17
17
  # Pre-fill input line
18
18
  readline.set_startup_hook(lambda: readline.insert_text(command))
19
19
  try:
@@ -21,11 +21,11 @@ def execute_command(command: str) -> None:
21
21
  if edited_command.strip(): # Ensure command is not empty
22
22
  os.system(edited_command)
23
23
  except KeyboardInterrupt:
24
- print("Execution cancelled")
24
+ PrettyOutput.print("执行取消", OutputType.INFO)
25
25
  finally:
26
26
  readline.set_startup_hook() # Clear pre-filled
27
27
  except Exception as e:
28
- PrettyOutput.print(f"Failed to execute command: {str(e)}", OutputType.ERROR)
28
+ PrettyOutput.print(f"执行命令失败: {str(e)}", OutputType.WARNING)
29
29
 
30
30
 
31
31
  def process_request(request: str) -> Optional[str]:
@@ -85,14 +85,14 @@ Remember: Only return the command itself, without any additional content.
85
85
  return None
86
86
 
87
87
  except Exception as e:
88
- PrettyOutput.print(f"Failed to process request: {str(e)}", OutputType.ERROR)
88
+ PrettyOutput.print(f"处理请求失败: {str(e)}", OutputType.WARNING)
89
89
  return None
90
90
 
91
91
  def main():
92
92
  # 创建参数解析器
93
93
  init_env()
94
94
  parser = argparse.ArgumentParser(
95
- description="Convert natural language requirements to shell commands",
95
+ description="将自然语言要求转换为shell命令",
96
96
  formatter_class=argparse.RawDescriptionHelpFormatter,
97
97
  epilog="""
98
98
  Example:
@@ -104,7 +104,7 @@ Example:
104
104
  # 添加参数
105
105
  parser.add_argument(
106
106
  "request",
107
- help="Describe the operation you want to perform in natural language"
107
+ help="描述您想要执行的操作, 用自然语言描述"
108
108
  )
109
109
 
110
110
  # 解析参数
@@ -45,7 +45,7 @@ class AskCodebaseTool:
45
45
  question = args["question"]
46
46
  top_k = args.get("top_k", 20)
47
47
 
48
- PrettyOutput.print(f"Analyzing codebase for question: {question}", OutputType.INFO)
48
+ PrettyOutput.print(f"正在分析代码库以回答问题: {question}", OutputType.INFO)
49
49
 
50
50
  # Create new CodeBase instance
51
51
  git_root = find_git_root()
@@ -61,8 +61,8 @@ class AskCodebaseTool:
61
61
  }
62
62
 
63
63
  except Exception as e:
64
- error_msg = f"Failed to analyze codebase: {str(e)}"
65
- PrettyOutput.print(error_msg, OutputType.ERROR)
64
+ error_msg = f"分析代码库失败: {str(e)}"
65
+ PrettyOutput.print(error_msg, OutputType.WARNING)
66
66
  return {
67
67
  "success": False,
68
68
  "stdout": "",
@@ -30,10 +30,10 @@ class AskUserTool:
30
30
  question = args["question"]
31
31
 
32
32
  # Display the question
33
- PrettyOutput.print(f"Question: {question}", OutputType.SYSTEM)
33
+ PrettyOutput.print(f"问题: {question}", OutputType.SYSTEM)
34
34
 
35
35
  # Get user input
36
- user_response = get_multiline_input("Please enter your answer (input empty line to end)")
36
+ user_response = get_multiline_input("请输入您的答案 (输入空行结束)")
37
37
 
38
38
  return {
39
39
  "success": True,
@@ -31,7 +31,7 @@ class CreateCodeAgentTool:
31
31
  # Step 1: Handle uncommitted changes
32
32
  start_commit = None
33
33
  if has_uncommitted_changes():
34
- PrettyOutput.print("Found uncommitted changes, committing first...", OutputType.INFO)
34
+ PrettyOutput.print("发现未提交的更改,正在提交...", OutputType.INFO)
35
35
  git_commiter = GitCommitTool()
36
36
  result = git_commiter.execute({})
37
37
  if not result["success"]:
@@ -45,7 +45,7 @@ class CreateCodeAgentTool:
45
45
  start_commit = self._get_current_commit()
46
46
 
47
47
  # Step 2: Development
48
- PrettyOutput.print("Starting development...", OutputType.INFO)
48
+ PrettyOutput.print("开始开发...", OutputType.INFO)
49
49
  agent = CodeAgent()
50
50
  agent.run(requirement)
51
51
 
@@ -53,7 +53,7 @@ class CreateCodeAgentTool:
53
53
  end_commit = self._get_current_commit()
54
54
 
55
55
  # Step 3: Code Review
56
- PrettyOutput.print("Starting code review...", OutputType.INFO)
56
+ PrettyOutput.print("开始代码审查...", OutputType.INFO)
57
57
  reviewer = CodeReviewTool()
58
58
  review_result = reviewer.execute({
59
59
  "review_type": "range",
@@ -69,15 +69,15 @@ class CreateCodeAgentTool:
69
69
  }
70
70
 
71
71
  # Step 4: Generate Summary
72
- summary = f"""Development Summary:
72
+ summary = f"""开发总结:
73
73
 
74
- Start Commit: {start_commit}
75
- End Commit: {end_commit}
74
+ 开始提交: {start_commit}
75
+ 结束提交: {end_commit}
76
76
 
77
- Requirement:
77
+ 需求:
78
78
  {requirement}
79
79
 
80
- Code Review Result:
80
+ 代码审查结果:
81
81
  {extract_code_report(review_result["stdout"])}
82
82
  """
83
83
 
@@ -50,7 +50,7 @@ class SubAgentTool:
50
50
  goal = args.get("goal", "")
51
51
  files = args.get("files", [])
52
52
 
53
- PrettyOutput.print(f"Create sub-agent: {agent_name}", OutputType.INFO)
53
+ PrettyOutput.print(f"创建子代理: {agent_name}", OutputType.INFO)
54
54
 
55
55
  # Build task description
56
56
  task_description = task
@@ -68,7 +68,7 @@ class SubAgentTool:
68
68
  )
69
69
 
70
70
  # Run sub-agent, pass file list
71
- PrettyOutput.print("Sub-agent starts executing task...", OutputType.INFO)
71
+ PrettyOutput.print("子代理开始执行任务...", OutputType.INFO)
72
72
  result = sub_agent.run(task_description, file_list=files)
73
73
 
74
74
  return {
@@ -40,7 +40,7 @@ class ShellTool:
40
40
  # Modify command to use script
41
41
  tee_command = f"script -q -c '{escaped_command}' {output_file}"
42
42
 
43
- PrettyOutput.print(f"Execute command: {command}", OutputType.INFO)
43
+ PrettyOutput.print(f"执行命令: {command}", OutputType.INFO)
44
44
 
45
45
  # Execute command
46
46
  return_code = os.system(tee_command)
@@ -55,7 +55,7 @@ class ShellTool:
55
55
  if len(lines) > 2:
56
56
  output = "\n".join(lines[1:-1])
57
57
  except Exception as e:
58
- output = f"Failed to read output file: {str(e)}"
58
+ output = f"读取输出文件失败: {str(e)}"
59
59
  finally:
60
60
  # Clean up temporary file
61
61
  Path(output_file).unlink(missing_ok=True)
@@ -43,7 +43,7 @@ class FileOperationTool:
43
43
 
44
44
  # Record the operation and the full path
45
45
  abs_path = os.path.abspath(filepath)
46
- PrettyOutput.print(f"File operation: {operation} - {abs_path}", OutputType.INFO)
46
+ PrettyOutput.print(f"文件操作: {operation} - {abs_path}", OutputType.INFO)
47
47
 
48
48
  if operation == "exists":
49
49
  exists = os.path.exists(filepath)
@@ -4,7 +4,7 @@ from typing import Dict, Any
4
4
 
5
5
  import yaml
6
6
  from jarvis.jarvis_platform.registry import PlatformRegistry
7
- from jarvis.utils import OutputType, PrettyOutput, init_env
7
+ from jarvis.utils import OutputType, PrettyOutput, has_uncommitted_changes, init_env
8
8
  import sys
9
9
 
10
10
 
@@ -25,7 +25,10 @@ class GitCommitTool:
25
25
  def execute(self, args: Dict) -> Dict[str, Any]:
26
26
  """Execute automatic commit process"""
27
27
  try:
28
- PrettyOutput.print("Add files to commit...", OutputType.SYSTEM)
28
+ if not has_uncommitted_changes():
29
+ PrettyOutput.print("没有未提交的更改", OutputType.SUCCESS)
30
+ return {"success": True, "stdout": "No uncommitted changes", "stderr": ""}
31
+ PrettyOutput.print("准备添加文件到提交...", OutputType.SYSTEM)
29
32
  os.system("git add .")
30
33
  PrettyOutput.print("Get diff...", OutputType.SYSTEM)
31
34
  diff = os.popen("git diff --cached --exit-code").read()
@@ -40,17 +43,17 @@ class GitCommitTool:
40
43
 
41
44
  {diff}
42
45
  '''
43
- PrettyOutput.print("Generate commit message...", OutputType.SYSTEM)
46
+ PrettyOutput.print("生成提交消息...", OutputType.SYSTEM)
44
47
  platform = PlatformRegistry().get_codegen_platform()
45
48
  platform.set_suppress_output(True)
46
49
  commit_message = platform.chat_until_success(prompt)
47
50
  commit_message = self._extract_commit_message(commit_message)
48
- PrettyOutput.print("Commit...", OutputType.INFO)
51
+ PrettyOutput.print("提交...", OutputType.INFO)
49
52
  os.popen(f"git commit -m '{commit_message}'")
50
53
 
51
54
  commit_hash = self._get_last_commit_hash()
52
55
 
53
- PrettyOutput.section(f"Commit hash: {commit_hash}\nCommit message: {commit_message}", OutputType.SUCCESS)
56
+ PrettyOutput.section(f"提交哈希: {commit_hash}\n提交消息: {commit_message}", OutputType.SUCCESS)
54
57
 
55
58
  return {"success": True, "stdout": yaml.safe_dump({"commit_hash": commit_hash, "commit_message": commit_message}), "stderr": ""}
56
59
 
@@ -47,7 +47,7 @@ class MethodologyTool:
47
47
  with open(self.methodology_file, 'w', encoding='utf-8') as f:
48
48
  yaml.safe_dump({}, f, allow_unicode=True)
49
49
  except Exception as e:
50
- PrettyOutput.print(f"Failed to create methodology file: {str(e)}", OutputType.ERROR)
50
+ PrettyOutput.print(f"创建方法论文件失败:{str(e)}", OutputType.ERROR)
51
51
 
52
52
  def _load_methodologies(self) -> Dict:
53
53
  """Load all methodologies"""
@@ -55,7 +55,7 @@ class MethodologyTool:
55
55
  with open(self.methodology_file, 'r', encoding='utf-8') as f:
56
56
  return yaml.safe_load(f) or {}
57
57
  except Exception as e:
58
- PrettyOutput.print(f"Failed to load methodologies: {str(e)}", OutputType.ERROR)
58
+ PrettyOutput.print(f"加载方法论失败: {str(e)}", OutputType.ERROR)
59
59
  return {}
60
60
 
61
61
  def _save_methodologies(self, methodologies: Dict):
@@ -64,7 +64,7 @@ class MethodologyTool:
64
64
  with open(self.methodology_file, 'w', encoding='utf-8') as f:
65
65
  yaml.safe_dump(methodologies, f, allow_unicode=True)
66
66
  except Exception as e:
67
- PrettyOutput.print(f"Failed to save methodologies: {str(e)}", OutputType.ERROR)
67
+ PrettyOutput.print(f"保存方法论失败: {str(e)}", OutputType.ERROR)
68
68
 
69
69
  def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
70
70
  """Execute the operation of managing methodologies
@@ -87,11 +87,11 @@ class RAGTool:
87
87
 
88
88
  # If you need to rebuild the index or the index does not exist
89
89
  if rebuild_index or not rag.is_index_built():
90
- PrettyOutput.print("Building document index...", OutputType.INFO)
90
+ PrettyOutput.print("正在构建文档索引...", OutputType.INFO)
91
91
  rag.build_index(dir_path)
92
92
 
93
93
  # Execute question and answer
94
- PrettyOutput.print(f"Question: {question}", OutputType.INFO)
94
+ PrettyOutput.print(f"问题: {question}", OutputType.INFO)
95
95
  response = rag.ask(question)
96
96
 
97
97
  if response is None:
@@ -108,7 +108,7 @@ class RAGTool:
108
108
  }
109
109
 
110
110
  except Exception as e:
111
- PrettyOutput.print(f"Document question and answer failed: {str(e)}", OutputType.ERROR)
111
+ PrettyOutput.print(f"文档问答失败:{str(e)}", OutputType.ERROR)
112
112
  return {
113
113
  "success": False,
114
114
  "stdout": "",
@@ -51,7 +51,7 @@ class ReadCodeTool:
51
51
 
52
52
  # Record the operation and the full path
53
53
  abs_path = os.path.abspath(filepath)
54
- PrettyOutput.print(f"Reading code file: {abs_path}", OutputType.INFO)
54
+ PrettyOutput.print(f"正在读取代码文件:{abs_path}", OutputType.INFO)
55
55
 
56
56
  # Check if file exists
57
57
  if not os.path.exists(filepath):
@@ -5,7 +5,7 @@ from jarvis.utils import PrettyOutput, OutputType
5
5
 
6
6
  class WebpageTool:
7
7
  name = "read_webpage"
8
- description = "Read webpage content, extract title and text"
8
+ description = "Read webpage content, extract title, text and hyperlinks"
9
9
  parameters = {
10
10
  "type": "object",
11
11
  "properties": {
@@ -28,7 +28,7 @@ class WebpageTool:
28
28
  }
29
29
 
30
30
  # Send request
31
- PrettyOutput.print(f"Reading webpage: {url}", OutputType.INFO)
31
+ PrettyOutput.print(f"正在读取网页:{url}", OutputType.INFO)
32
32
  response = requests.get(url, headers=headers, timeout=10)
33
33
  response.raise_for_status()
34
34
 
@@ -46,16 +46,29 @@ class WebpageTool:
46
46
  title = soup.title.string if soup.title else ""
47
47
  title = title.strip() if title else "No title"
48
48
 
49
- # Extract text
50
- text = soup.get_text(separator='\n', strip=True)
51
- lines = [line.strip() for line in text.splitlines() if line.strip()]
49
+ # Extract text and links
50
+ text_parts = []
51
+ links = []
52
+
53
+ # Process content and collect links
54
+ for element in soup.descendants:
55
+ if element.name == 'a' and element.get('href'): # type: ignore
56
+ href = element.get('href') # type: ignore
57
+ text = element.get_text(strip=True)
58
+ if text and href:
59
+ links.append(f"[{text}]({href})")
60
+ elif isinstance(element, str) and element.strip():
61
+ text_parts.append(element.strip())
52
62
 
53
63
  # Build output
54
64
  output = [
55
65
  f"Title: {title}",
56
66
  "",
57
67
  "Text content:",
58
- "\n".join(lines)
68
+ "\n".join(text_parts),
69
+ "",
70
+ "Links found:",
71
+ "\n".join(links) if links else "No links found"
59
72
  ]
60
73
 
61
74
  return {
@@ -71,7 +71,7 @@ class ToolRegistry:
71
71
  """Use specified tools"""
72
72
  missing_tools = [tool_name for tool_name in name if tool_name not in self.tools]
73
73
  if missing_tools:
74
- PrettyOutput.print(f"Tools {missing_tools} do not exist, available tools: {', '.join(self.tools.keys())}", OutputType.WARNING)
74
+ PrettyOutput.print(f"工具 {missing_tools} 不存在,可用的工具有: {', '.join(self.tools.keys())}", OutputType.WARNING)
75
75
  self.tools = {tool_name: self.tools[tool_name] for tool_name in name}
76
76
 
77
77
  def dont_use_tools(self, names: List[str]):
@@ -116,7 +116,7 @@ class ToolRegistry:
116
116
  try:
117
117
  p_file_path = Path(file_path).resolve() # Get the absolute path
118
118
  if not p_file_path.exists() or not p_file_path.is_file():
119
- PrettyOutput.print(f"File does not exist: {p_file_path}", OutputType.ERROR)
119
+ PrettyOutput.print(f"文件不存在: {p_file_path}", OutputType.ERROR)
120
120
  return False
121
121
 
122
122
  # Add the parent directory to sys.path temporarily
@@ -167,7 +167,7 @@ class ToolRegistry:
167
167
  sys.path.remove(parent_dir)
168
168
 
169
169
  except Exception as e:
170
- PrettyOutput.print(f"Failed to load tool from {Path(file_path).name}: {str(e)}", OutputType.ERROR)
170
+ PrettyOutput.print(f" {Path(file_path).name} 加载工具失败: {str(e)}", OutputType.ERROR)
171
171
  return False
172
172
 
173
173
  def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
@@ -215,12 +215,12 @@ arguments:
215
215
  try:
216
216
  args = json.loads(args)
217
217
  except json.JSONDecodeError:
218
- PrettyOutput.print(f"Invalid tool parameters format: {name} {tool_call_help}", OutputType.ERROR)
218
+ PrettyOutput.print(f"工具参数格式无效: {name} {tool_call_help}", OutputType.ERROR)
219
219
  return ""
220
220
 
221
221
  # Display tool call information
222
- PrettyOutput.section(f"Executing tool: {name}", OutputType.TOOL)
223
- params = "Parameters:\n"
222
+ PrettyOutput.section(f"执行工具: {name}", OutputType.TOOL)
223
+ params = "参数:\n"
224
224
  if isinstance(args, dict):
225
225
  for key, value in args.items():
226
226
  params += f"{key} = {value}\n"
@@ -245,12 +245,12 @@ arguments:
245
245
  # Process the result
246
246
  if result["success"]:
247
247
 
248
- PrettyOutput.section("Execution successful", OutputType.SUCCESS)
248
+ PrettyOutput.section("执行成功", OutputType.SUCCESS)
249
249
 
250
250
  # If the output exceeds 4k characters, use a large model to summarize
251
251
  if get_context_token_count(output) > self.max_token_count:
252
252
  try:
253
- PrettyOutput.print("Output is too long, summarizing...", OutputType.PROGRESS)
253
+ PrettyOutput.print("输出过长,正在总结...", OutputType.PROGRESS)
254
254
  model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
255
255
 
256
256
  # If the output exceeds the maximum context length, only take the last part
@@ -282,11 +282,11 @@ Please provide a summary:"""
282
282
  --- Summary ends ---"""
283
283
 
284
284
  except Exception as e:
285
- PrettyOutput.print(f"Summary failed: {str(e)}", OutputType.ERROR)
285
+ PrettyOutput.print(f"总结失败: {str(e)}", OutputType.ERROR)
286
286
  output = f"Output is too long ({len(output)} characters), it is recommended to view the original output.\nPreview of the first 300 characters:\n{output[:300]}..."
287
287
 
288
288
  else:
289
- PrettyOutput.section("Execution failed", OutputType.WARNING)
289
+ PrettyOutput.section("执行失败", OutputType.WARNING)
290
290
  PrettyOutput.print(result["stderr"], OutputType.WARNING)
291
291
 
292
292
  if len(tool_calls) > 1:
@@ -294,5 +294,5 @@ Please provide a summary:"""
294
294
  return output
295
295
 
296
296
  except Exception as e:
297
- PrettyOutput.print(f"Tool execution failed: {str(e)}", OutputType.ERROR)
297
+ PrettyOutput.print(f"工具执行失败:{str(e)}", OutputType.ERROR)
298
298
  return f"Tool call failed: {str(e)}"