jarvis-ai-assistant 0.1.111__py3-none-any.whl → 0.1.112__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 +40 -34
  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 +4 -4
  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 +18 -20
  39. jarvis_ai_assistant-0.1.112.dist-info/METADATA +460 -0
  40. jarvis_ai_assistant-0.1.112.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.112.dist-info}/LICENSE +0 -0
  44. {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/WHEEL +0 -0
  45. {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/entry_points.txt +0 -0
  46. {jarvis_ai_assistant-0.1.111.dist-info → jarvis_ai_assistant-0.1.112.dist-info}/top_level.txt +0 -0
@@ -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)
@@ -25,7 +25,7 @@ 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
+ PrettyOutput.print("准备添加文件到提交...", OutputType.SYSTEM)
29
29
  os.system("git add .")
30
30
  PrettyOutput.print("Get diff...", OutputType.SYSTEM)
31
31
  diff = os.popen("git diff --cached --exit-code").read()
@@ -40,17 +40,17 @@ class GitCommitTool:
40
40
 
41
41
  {diff}
42
42
  '''
43
- PrettyOutput.print("Generate commit message...", OutputType.SYSTEM)
43
+ PrettyOutput.print("生成提交消息...", OutputType.SYSTEM)
44
44
  platform = PlatformRegistry().get_codegen_platform()
45
45
  platform.set_suppress_output(True)
46
46
  commit_message = platform.chat_until_success(prompt)
47
47
  commit_message = self._extract_commit_message(commit_message)
48
- PrettyOutput.print("Commit...", OutputType.INFO)
48
+ PrettyOutput.print("提交...", OutputType.INFO)
49
49
  os.popen(f"git commit -m '{commit_message}'")
50
50
 
51
51
  commit_hash = self._get_last_commit_hash()
52
52
 
53
- PrettyOutput.section(f"Commit hash: {commit_hash}\nCommit message: {commit_message}", OutputType.SUCCESS)
53
+ PrettyOutput.section(f"提交哈希: {commit_hash}\n提交消息: {commit_message}", OutputType.SUCCESS)
54
54
 
55
55
  return {"success": True, "stdout": yaml.safe_dump({"commit_hash": commit_hash, "commit_message": commit_message}), "stderr": ""}
56
56
 
@@ -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)}"
@@ -1,6 +1,6 @@
1
1
  from typing import Dict, Any, List
2
2
  from jarvis.jarvis_platform.registry import PlatformRegistry
3
- from jarvis.utils import PrettyOutput, OutputType
3
+ from jarvis.utils import PrettyOutput, OutputType, get_context_token_count, get_max_token_count
4
4
  from jarvis.jarvis_tools.read_webpage import WebpageTool
5
5
  from playwright.sync_api import sync_playwright
6
6
  from urllib.parse import quote
@@ -58,7 +58,7 @@ def bing_search(query):
58
58
  return summaries
59
59
 
60
60
  except Exception as error:
61
- PrettyOutput.print(f"Search error: {str(error)}", OutputType.ERROR)
61
+ PrettyOutput.print(f"搜索错误:{str(error)}", OutputType.ERROR)
62
62
  return None
63
63
 
64
64
  class SearchTool:
@@ -106,28 +106,89 @@ class SearchTool:
106
106
  })
107
107
  return formatted_results
108
108
  except Exception as e:
109
- PrettyOutput.print(f"Search request failed: {str(e)}", OutputType.ERROR)
109
+ PrettyOutput.print(f"搜索请求失败:{str(e)}", OutputType.ERROR)
110
110
  return []
111
111
 
112
112
  def _extract_info(self, contents: List[str], question: str) -> str:
113
113
  """Use language model to extract key information from web content"""
114
- prompt = f"""Please answer the question based on the following search results: {question}
114
+ try:
115
+ # Reserve tokens for prompt and response
116
+ max_tokens = get_max_token_count()
117
+ reserved_tokens = 2000 # Reserve tokens for prompt template and response
118
+ available_tokens = max_tokens - reserved_tokens
119
+
120
+ # Split contents into batches
121
+ batches = []
122
+ current_batch = []
123
+ current_tokens = 0
124
+
125
+ for content in contents:
126
+ content_tokens = get_context_token_count(content)
127
+
128
+ # If adding this content would exceed limit, start new batch
129
+ if current_tokens + content_tokens > available_tokens:
130
+ if current_batch:
131
+ batches.append(current_batch)
132
+ current_batch = [content]
133
+ current_tokens = content_tokens
134
+ else:
135
+ current_batch.append(content)
136
+ current_tokens += content_tokens
137
+
138
+ # Add final batch
139
+ if current_batch:
140
+ batches.append(current_batch)
115
141
 
116
- Search results content:
142
+ # Process each batch
143
+ batch_results = []
144
+ for i, batch in enumerate(batches, 1):
145
+ PrettyOutput.print(f"正在处理批次 {i}/{len(batches)}...", OutputType.PROGRESS)
146
+
147
+ prompt = f"""Please analyze these search results to answer the question: {question}
148
+
149
+ Search results content (Batch {i}/{len(batches)}):
117
150
  {'-' * 40}
118
- {''.join(contents)}
151
+ {''.join(batch)}
119
152
  {'-' * 40}
120
153
 
121
- Please provide a concise and accurate answer, focusing on information directly related to the question. If there is no relevant information in the search results, please clearly state that.
122
- When answering, pay attention to:
123
- 1. Maintain objectivity, providing information based solely on search results
124
- 2. If there are conflicts between different sources, point out the differences
125
- 3. Appropriately cite information sources
126
- 4. If the information is incomplete or uncertain, please explain"""
154
+ Please extract key information related to the question. Focus on:
155
+ 1. Relevant facts and details
156
+ 2. Maintaining objectivity
157
+ 3. Citing sources when appropriate
158
+ 4. Noting any uncertainties
159
+
160
+ Format your response as a clear summary of findings from this batch."""
161
+
162
+ response = self.model.chat_until_success(prompt)
163
+ batch_results.append(response)
164
+
165
+ # If only one batch, return its result directly
166
+ if len(batch_results) == 1:
167
+ return batch_results[0]
168
+
169
+ # Synthesize results from all batches
170
+ batch_findings = '\n\n'.join(f'Batch {i+1}:\n{result}' for i, result in enumerate(batch_results))
171
+ separator = '-' * 40
172
+
173
+ synthesis_prompt = f"""Please provide a comprehensive answer to the original question by synthesizing the findings from multiple batches of search results.
174
+
175
+ Original Question: {question}
176
+
177
+ Findings from each batch:
178
+ {separator}
179
+ {batch_findings}
180
+ {separator}
181
+
182
+ Please synthesize a final answer that:
183
+ 1. Combines key insights from all batches
184
+ 2. Resolves any contradictions between sources
185
+ 3. Maintains clear source attribution
186
+ 4. Acknowledges any remaining uncertainties
187
+ 5. Provides a coherent and complete response to the original question"""
188
+
189
+ final_response = self.model.chat_until_success(synthesis_prompt)
190
+ return final_response
127
191
 
128
- try:
129
- response = self.model.chat_until_success(prompt)
130
- return response
131
192
  except Exception as e:
132
193
  return f"Information extraction failed: {str(e)}"
133
194
 
@@ -139,8 +200,8 @@ When answering, pay attention to:
139
200
  max_results = args.get("max_results", 3)
140
201
 
141
202
  # Print search information
142
- PrettyOutput.print(f"Search query: {query}", OutputType.INFO)
143
- PrettyOutput.print(f"Related question: {question}", OutputType.INFO)
203
+ PrettyOutput.print(f"搜索关键词: {query}", OutputType.INFO)
204
+ PrettyOutput.print(f"相关问题: {question}", OutputType.INFO)
144
205
 
145
206
  # Get search results
146
207
  results = self._search(query, max_results)
@@ -155,13 +216,13 @@ When answering, pay attention to:
155
216
  contents = []
156
217
  for i, result in enumerate(results, 1):
157
218
  try:
158
- PrettyOutput.print(f"Reading result {i}/{len(results)}... {result['title']} - {result['href']}", OutputType.PROGRESS)
219
+ PrettyOutput.print(f"正在读取结果 {i}/{len(results)}... {result['title']} - {result['href']}", OutputType.PROGRESS)
159
220
  webpage_result = self.webpage_tool.execute({"url": result["href"]})
160
221
  if webpage_result["success"]:
161
222
  contents.append(f"\nSource {i}: {result['href']}\n")
162
223
  contents.append(webpage_result["stdout"])
163
224
  except Exception as e:
164
- PrettyOutput.print(f"Failed to read result {i}: {str(e)}", OutputType.WARNING)
225
+ PrettyOutput.print(f"读取结果失败 {i}: {str(e)}", OutputType.WARNING)
165
226
  continue
166
227
 
167
228
  if not contents:
@@ -172,7 +233,7 @@ When answering, pay attention to:
172
233
  }
173
234
 
174
235
  # Extract information
175
- PrettyOutput.print("Analyzing search results...", OutputType.PROGRESS)
236
+ PrettyOutput.print("正在分析搜索结果...", OutputType.PROGRESS)
176
237
  analysis = self._extract_info(contents, question)
177
238
 
178
239
  return {
@@ -200,15 +261,15 @@ def main():
200
261
  args = parser.parse_args()
201
262
 
202
263
  try:
203
- PrettyOutput.print(f"Searching: {args.query}", OutputType.INFO)
264
+ PrettyOutput.print(f"搜索: {args.query}", OutputType.INFO)
204
265
 
205
266
  results = bing_search(args.query)
206
267
 
207
268
  if not results:
208
- PrettyOutput.print("No search results found", OutputType.WARNING)
269
+ PrettyOutput.print("未找到搜索结果", OutputType.WARNING)
209
270
  sys.exit(1)
210
271
 
211
- PrettyOutput.print(f"\nFound {len(results)} results:", OutputType.INFO)
272
+ PrettyOutput.print(f"\n找到 {len(results)} 个结果:", OutputType.INFO)
212
273
 
213
274
  for i, result in enumerate(results[:args.max], 1):
214
275
  output = []
@@ -217,16 +278,16 @@ def main():
217
278
  output.append(f"{i}. {result['href']}")
218
279
  else:
219
280
  output.append(f"{i}. {result['title']}")
220
- output.append(f"Link: {result['href']}")
281
+ output.append(f"链接: {result['href']}")
221
282
  if result['abstract']:
222
- output.append(f"Abstract: {result['abstract']}")
283
+ output.append(f"摘要: {result['abstract']}")
223
284
  PrettyOutput.print("\n".join(output), OutputType.INFO)
224
285
 
225
286
  except KeyboardInterrupt:
226
- PrettyOutput.print("Search cancelled", OutputType.WARNING)
287
+ PrettyOutput.print("搜索已取消", OutputType.WARNING)
227
288
  sys.exit(1)
228
289
  except Exception as e:
229
- PrettyOutput.print(f"Execution error: {str(e)}", OutputType.ERROR)
290
+ PrettyOutput.print(f"执行错误: {str(e)}", OutputType.ERROR)
230
291
  sys.exit(1)
231
292
 
232
293
  if __name__ == "__main__":
@@ -33,7 +33,7 @@ class CodeFileSelecterTool:
33
33
  related_files = args.get("related_files", [])
34
34
  root_dir = args.get("root_dir", ".").strip()
35
35
 
36
- PrettyOutput.print("Starting interactive file selection...", OutputType.INFO)
36
+ PrettyOutput.print("开始交互式文件选择...", OutputType.INFO)
37
37
 
38
38
  # Use file_select module to handle file selection
39
39
  selected_files = select_files(