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/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Jarvis AI Assistant"""
2
2
 
3
- __version__ = "0.1.111"
3
+ __version__ = "0.1.113"
jarvis/agent.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import argparse
2
+ from ast import Tuple
2
3
  import time
3
4
  from typing import Callable, Dict, List, Optional
4
5
 
@@ -33,12 +34,14 @@ class Agent:
33
34
  system_prompt: str,
34
35
  name: str = "Jarvis",
35
36
  is_sub_agent: bool = False,
36
- tool_registry: Optional[ToolRegistry] = None,
37
- platform: Optional[BasePlatform] = None,
37
+ tool_registry: Optional[ToolRegistry|List[str]] = None,
38
+ platform: Optional[BasePlatform]|Optional[str] = None,
39
+ model_name: Optional[str] = None,
38
40
  summary_prompt: Optional[str] = None,
39
41
  auto_complete: Optional[bool] = None,
40
42
  output_handler_before_tool: Optional[List[Callable]] = None,
41
43
  output_handler_after_tool: Optional[List[Callable]] = None,
44
+ input_handler: Optional[List[Callable]] = None,
42
45
  use_methodology: Optional[bool] = None,
43
46
  record_methodology: Optional[bool] = None,
44
47
  need_summary: Optional[bool] = None,
@@ -61,12 +64,35 @@ class Agent:
61
64
  need_summary: Whether to generate summaries
62
65
  max_context_length: Maximum context length
63
66
  """
64
- PrettyOutput.print(f"Welcome to Jarvis, your AI assistant, Initiating...", OutputType.SYSTEM)
67
+ PrettyOutput.print(f"欢迎使用Jarvis,你的AI助手,正在初始化...", OutputType.SYSTEM)
68
+
69
+ # 初始化平台和模型
65
70
  if platform is not None:
66
- self.model = platform
71
+ if isinstance(platform, str):
72
+ self.model = PlatformRegistry().create_platform(platform)
73
+ if self.model is None:
74
+ PrettyOutput.print(f"平台 {platform} 不存在,将使用普通模型", OutputType.WARNING)
75
+ self.model = PlatformRegistry().get_normal_platform()
76
+ else:
77
+ self.model = platform
67
78
  else:
68
79
  self.model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
69
- self.tool_registry = tool_registry if tool_registry else ToolRegistry()
80
+
81
+ if model_name is not None:
82
+ self.model.set_model_name(model_name)
83
+
84
+
85
+ # 初始化工具
86
+ if tool_registry is not None:
87
+ if isinstance(tool_registry, ToolRegistry):
88
+ self.tool_registry = tool_registry
89
+ elif isinstance(tool_registry, List):
90
+ self.tool_registry = ToolRegistry()
91
+ self.tool_registry.use_tools(tool_registry)
92
+ else:
93
+ self.tool_registry = ToolRegistry()
94
+
95
+
70
96
  self.record_methodology = record_methodology if record_methodology is not None else is_record_methodology()
71
97
  self.use_methodology = use_methodology if use_methodology is not None else is_use_methodology()
72
98
  self.name = name
@@ -75,6 +101,7 @@ class Agent:
75
101
  self.conversation_length = 0 # Use length counter instead
76
102
  self.system_prompt = system_prompt
77
103
  self.need_summary = need_summary if need_summary is not None else is_need_summary()
104
+ self.input_handler = input_handler if input_handler is not None else []
78
105
  # Load configuration from environment variables
79
106
  self.output_handler_before_tool = output_handler_before_tool if output_handler_before_tool else []
80
107
  self.output_handler_after_tool = output_handler_after_tool if output_handler_after_tool else []
@@ -96,11 +123,11 @@ Please describe in concise bullet points, highlighting important information.
96
123
 
97
124
  self.auto_complete = auto_complete if auto_complete is not None else is_auto_complete()
98
125
 
99
- PrettyOutput.section(f"Jarvis initialized - With {self.model.name()}", OutputType.SYSTEM)
126
+ PrettyOutput.section(f"Jarvis 初始化完成 - 使用 {self.model.name()} 模型", OutputType.SYSTEM)
100
127
 
101
128
  tools = self.tool_registry.get_all_tools()
102
129
  if tools:
103
- PrettyOutput.section(f"Available tools: {', '.join([tool['name'] for tool in tools])}", OutputType.SYSTEM)
130
+ PrettyOutput.section(f"可用工具: {', '.join([tool['name'] for tool in tools])}", OutputType.SYSTEM)
104
131
 
105
132
 
106
133
  tools_prompt = self.tool_registry.load_tools()
@@ -181,12 +208,16 @@ Please describe in concise bullet points, highlighting important information.
181
208
  Will retry with exponential backoff up to 30 seconds between retries
182
209
  """
183
210
  sleep_time = 5
211
+
212
+ for handler in self.input_handler:
213
+ message = handler(message)
214
+
184
215
  while True:
185
- ret = self.model.chat_until_success(message)
216
+ ret = self.model.chat_until_success(message) # type: ignore
186
217
  if ret:
187
218
  return ret
188
219
  else:
189
- PrettyOutput.print(f"Model call failed, retrying... waiting {sleep_time}s", OutputType.INFO)
220
+ PrettyOutput.print(f"模型调用失败,正在重试... 等待 {sleep_time}s", OutputType.INFO)
190
221
  time.sleep(sleep_time)
191
222
  sleep_time *= 2
192
223
  if sleep_time > 30:
@@ -209,7 +240,7 @@ Please describe in concise bullet points, highlighting important information.
209
240
  """
210
241
  # Create a new model instance to summarize, avoid affecting the main conversation
211
242
 
212
- PrettyOutput.print("Summarizing conversation history, preparing to generate summary, starting new conversation...", OutputType.PROGRESS)
243
+ PrettyOutput.print("总结对话历史,准备生成摘要,开始新对话...", OutputType.PROGRESS)
213
244
 
214
245
  prompt = """Please summarize the key information from the previous conversation, including:
215
246
  1. Current task objective
@@ -222,7 +253,7 @@ Please describe in concise bullet points, highlighting important information. Do
222
253
  """
223
254
 
224
255
  try:
225
- summary = self.model.chat_until_success(self.prompt + "\n" + prompt)
256
+ summary = self._call_model(self.prompt + "\n" + prompt)
226
257
 
227
258
  # 清空当前对话历史,但保留系统消息
228
259
  self.conversation_length = 0 # Reset conversation length
@@ -237,7 +268,7 @@ Please continue the task based on the above information.
237
268
  self.conversation_length = len(self.prompt) # 设置新的起始长度
238
269
 
239
270
  except Exception as e:
240
- PrettyOutput.print(f"Failed to summarize conversation history: {str(e)}", OutputType.ERROR)
271
+ PrettyOutput.print(f"总结对话历史失败: {str(e)}", OutputType.ERROR)
241
272
 
242
273
  def _complete_task(self) -> str:
243
274
  """Complete the current task and generate summary if needed.
@@ -249,7 +280,7 @@ Please continue the task based on the above information.
249
280
  - For main agent: May generate methodology if enabled
250
281
  - For sub-agent: May generate summary if enabled
251
282
  """
252
- PrettyOutput.section("Task completed", OutputType.SUCCESS)
283
+ PrettyOutput.section("任务完成", OutputType.SUCCESS)
253
284
 
254
285
  if not self.is_sub_agent:
255
286
  if self.record_methodology:
@@ -272,18 +303,18 @@ Please continue the task based on the above information.
272
303
  if tool_calls:
273
304
  self.tool_registry.handle_tool_calls(tool_calls)
274
305
  except Exception as e:
275
- PrettyOutput.print(f"Failed to handle methodology generation: {str(e)}", OutputType.ERROR)
306
+ PrettyOutput.print(f"处理方法论生成失败: {str(e)}", OutputType.ERROR)
276
307
 
277
308
  except Exception as e:
278
- PrettyOutput.print(f"Error generating methodology: {str(e)}", OutputType.ERROR)
309
+ PrettyOutput.print(f"生成方法论失败: {str(e)}", OutputType.ERROR)
279
310
 
280
- return "Task completed"
311
+ return "任务完成"
281
312
 
282
313
  if self.need_summary:
283
314
  self.prompt = self.summary_prompt
284
315
  return self._call_model(self.prompt)
285
316
 
286
- return "Task completed"
317
+ return "任务完成"
287
318
 
288
319
 
289
320
  def run(self, user_input: str, file_list: Optional[List[str]] = None) -> str:
@@ -306,12 +337,12 @@ Please continue the task based on the above information.
306
337
  add_agent(self.name)
307
338
 
308
339
  try:
309
- PrettyOutput.section("Preparing environment", OutputType.PLANNING)
340
+ PrettyOutput.section("准备环境", OutputType.PLANNING)
310
341
  if file_list:
311
- self.model.upload_files(file_list)
342
+ self.model.upload_files(file_list) # type: ignore
312
343
 
313
344
  # 显示任务开始
314
- PrettyOutput.section(f"Starting new task: {self.name}", OutputType.PLANNING)
345
+ PrettyOutput.section(f"开始新任务: {self.name}", OutputType.PLANNING)
315
346
 
316
347
  if self.first and self.use_methodology:
317
348
  self.prompt = f"{user_input}\n\n{load_methodology(user_input)}"
@@ -322,7 +353,7 @@ Please continue the task based on the above information.
322
353
  while True:
323
354
  try:
324
355
  # 显示思考状态
325
- PrettyOutput.print("Analyzing task...", OutputType.PROGRESS)
356
+ PrettyOutput.print("正在分析任务...", OutputType.PROGRESS)
326
357
 
327
358
  # 累加对话长度
328
359
  self.conversation_length += get_context_token_count(self.prompt)
@@ -342,13 +373,13 @@ Please continue the task based on the above information.
342
373
  try:
343
374
  result = Agent._extract_tool_calls(current_response)
344
375
  except Exception as e:
345
- PrettyOutput.print(f"Tool call error: {str(e)}", OutputType.ERROR)
376
+ PrettyOutput.print(f"工具调用错误: {str(e)}", OutputType.ERROR)
346
377
  self.prompt += f"Tool call error: {str(e)}"
347
378
  continue
348
379
 
349
380
  if len(result) > 0:
350
- if not self.execute_tool_confirm or user_confirm(f"Execute tool call: {result[0]['name']}?"):
351
- PrettyOutput.print("Executing tool call...", OutputType.PROGRESS)
381
+ if not self.execute_tool_confirm or user_confirm(f"执行工具调用: {result[0]['name']}?"):
382
+ PrettyOutput.print("正在执行工具调用...", OutputType.PROGRESS)
352
383
  tool_result = self.tool_registry.handle_tool_calls(result)
353
384
  self.prompt += tool_result
354
385
 
@@ -362,7 +393,7 @@ Please continue the task based on the above information.
362
393
  return self._complete_task()
363
394
 
364
395
  # 获取用户输入
365
- user_input = get_multiline_input(f"{self.name}: You can continue to input, or enter an empty line to end the current task")
396
+ user_input = get_multiline_input(f"{self.name}: 您可以继续输入,或输入空行来结束当前任务:")
366
397
 
367
398
  if user_input:
368
399
  self.prompt = user_input
@@ -372,11 +403,11 @@ Please continue the task based on the above information.
372
403
  return self._complete_task()
373
404
 
374
405
  except Exception as e:
375
- PrettyOutput.print(str(e), OutputType.ERROR)
406
+ PrettyOutput.print(f"任务失败: {str(e)}", OutputType.ERROR)
376
407
  return f"Task failed: {str(e)}"
377
408
 
378
409
  except Exception as e:
379
- PrettyOutput.print(str(e), OutputType.ERROR)
410
+ PrettyOutput.print(f"任务失败: {str(e)}", OutputType.ERROR)
380
411
  return f"Task failed: {str(e)}"
381
412
 
382
413
  finally:
@@ -391,7 +422,7 @@ Please continue the task based on the above information.
391
422
  3. Reset conversation length counter
392
423
  """
393
424
  self.prompt = ""
394
- self.model.reset()
425
+ self.model.reset() # type: ignore
395
426
  self.conversation_length = 0 # Reset conversation length
396
427
 
397
428
 
@@ -414,9 +445,9 @@ def _load_tasks() -> dict:
414
445
  if desc: # Ensure description is not empty
415
446
  tasks[str(name)] = str(desc)
416
447
  else:
417
- PrettyOutput.print("Warning: ~/.jarvis/pre-command file should contain a dictionary of task_name: task_description", OutputType.ERROR)
448
+ PrettyOutput.print("警告: ~/.jarvis/pre-command 文件应该包含一个字典,键为任务名称,值为任务描述", OutputType.ERROR)
418
449
  except Exception as e:
419
- PrettyOutput.print(f"Error loading ~/.jarvis/pre-command file: {str(e)}", OutputType.ERROR)
450
+ PrettyOutput.print(f"加载 ~/.jarvis/pre-command 文件失败: {str(e)}", OutputType.ERROR)
420
451
 
421
452
  # Check .jarvis/pre-command in current directory
422
453
  if os.path.exists(".jarvis/pre-command"):
@@ -430,9 +461,9 @@ def _load_tasks() -> dict:
430
461
  if desc: # Ensure description is not empty
431
462
  tasks[str(name)] = str(desc)
432
463
  else:
433
- PrettyOutput.print("Warning: .jarvis/pre-command file should contain a dictionary of task_name: task_description", OutputType.ERROR)
464
+ PrettyOutput.print("警告: .jarvis/pre-command 文件应该包含一个字典,键为任务名称,值为任务描述", OutputType.ERROR)
434
465
  except Exception as e:
435
- PrettyOutput.print(f"Error loading .jarvis/pre-command file: {str(e)}", OutputType.ERROR)
466
+ PrettyOutput.print(f"加载 .jarvis/pre-command 文件失败: {str(e)}", OutputType.ERROR)
436
467
 
437
468
 
438
469
  if is_use_methodology():
@@ -455,17 +486,17 @@ def _select_task(tasks: dict) -> str:
455
486
  # Convert tasks to list for ordered display
456
487
  task_names = list(tasks.keys())
457
488
 
458
- task_list = ["Available tasks:"]
489
+ task_list = ["可用任务:"]
459
490
  for i, name in enumerate(task_names, 1):
460
491
  task_list.append(f"[{i}] {name}")
461
- task_list.append("[0] Skip predefined tasks")
492
+ task_list.append("[0] 跳过预定义任务")
462
493
  PrettyOutput.print("\n".join(task_list), OutputType.INFO)
463
494
 
464
495
 
465
496
  while True:
466
497
  try:
467
498
  choice = prompt(
468
- "\nPlease select a task number (0 to skip): ",
499
+ "\n请选择一个任务编号(0 跳过预定义任务):",
469
500
  ).strip()
470
501
 
471
502
  if not choice:
@@ -478,14 +509,14 @@ def _select_task(tasks: dict) -> str:
478
509
  selected_name = task_names[choice - 1]
479
510
  return tasks[selected_name] # Return the task description
480
511
  else:
481
- PrettyOutput.print("Invalid choice. Please select a number from the list.", OutputType.ERROR)
512
+ PrettyOutput.print("无效的选择。请选择列表中的一个号码。", OutputType.WARNING)
482
513
 
483
514
  except KeyboardInterrupt:
484
515
  return "" # Return empty on Ctrl+C
485
516
  except EOFError:
486
517
  return "" # Return empty on Ctrl+D
487
518
  except Exception as e:
488
- PrettyOutput.print(f"Failed to select task: {str(e)}", OutputType.ERROR)
519
+ PrettyOutput.print(f"选择任务失败: {str(e)}", OutputType.ERROR)
489
520
  continue
490
521
 
491
522
  origin_agent_system_prompt = """You are Jarvis, an AI assistant with powerful problem-solving capabilities.
@@ -529,22 +560,22 @@ def main():
529
560
  if tasks:
530
561
  selected_task = _select_task(tasks)
531
562
  if selected_task:
532
- PrettyOutput.print(f"\nExecute task: {selected_task}", OutputType.INFO)
563
+ PrettyOutput.print(f"执行任务: {selected_task}", OutputType.INFO)
533
564
  agent.run(selected_task, args.files)
534
565
  return 0
535
566
 
536
567
  # 如果没有选择预定义任务,进入交互模式
537
568
  while True:
538
569
  try:
539
- user_input = get_multiline_input("Please enter your task (input empty line to exit):")
570
+ user_input = get_multiline_input("请输入你的任务(输入空行退出):")
540
571
  if not user_input:
541
572
  break
542
573
  agent.run(user_input, args.files)
543
574
  except Exception as e:
544
- PrettyOutput.print(f"Error: {str(e)}", OutputType.ERROR)
575
+ PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
545
576
 
546
577
  except Exception as e:
547
- PrettyOutput.print(f"Initialization error: {str(e)}", OutputType.ERROR)
578
+ PrettyOutput.print(f"初始化错误: {str(e)}", OutputType.ERROR)
548
579
  return 1
549
580
 
550
581
  return 0
@@ -34,9 +34,24 @@ class CodeAgent:
34
34
  3. Map out affected components and their interactions
35
35
  4. Plan changes that maintain system integrity
36
36
 
37
+ # Code Completeness Requirements
38
+ 1. Implementation Must Be Complete
39
+ • NO TODOs or placeholder comments
40
+ • NO unfinished functions
41
+ • NO stub implementations
42
+ • All error cases must be handled
43
+ • All edge cases must be covered
44
+
45
+ 2. Documentation Must Be Complete
46
+ • All functions must have docstrings
47
+ • All parameters must be documented
48
+ • Return values must be specified
49
+ • Exceptions must be documented
50
+ • Complex logic must be explained
51
+
37
52
  # Patch Format
38
53
  <PATCH>
39
- > /path/file start,end
54
+ > path/file start,end
40
55
  new_content
41
56
  </PATCH>
42
57
 
@@ -84,6 +99,7 @@ Key Rules:
84
99
  • Follow existing patterns exactly
85
100
  • Preserve all interfaces
86
101
  • Maintain backward compatibility
102
+ • Implement completely - no TODOs
87
103
 
88
104
  # File Handling
89
105
  Large Files (>200 lines):
@@ -105,7 +121,9 @@ Every Change Must:
105
121
  ✓ Match existing style exactly
106
122
  ✓ Handle errors consistently
107
123
  ✓ Maintain documentation
108
- ✓ Follow project patterns"""
124
+ ✓ Follow project patterns
125
+ ✓ Be completely implemented
126
+ ✓ Have no TODOs or stubs"""
109
127
  self.agent = Agent(system_prompt=code_system_prompt,
110
128
  name="CodeAgent",
111
129
  auto_complete=False,
@@ -196,17 +214,17 @@ def main():
196
214
  # Interactive mode
197
215
  while True:
198
216
  try:
199
- user_input = get_multiline_input("Please enter your requirement (input empty line to exit):")
217
+ user_input = get_multiline_input("请输入你的需求(输入空行退出):")
200
218
  if not user_input:
201
219
  break
202
220
  agent = CodeAgent()
203
221
  agent.run(user_input)
204
222
 
205
223
  except Exception as e:
206
- PrettyOutput.print(f"Error: {str(e)}", OutputType.ERROR)
224
+ PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
207
225
 
208
226
  except Exception as e:
209
- PrettyOutput.print(f"Initialization error: {str(e)}", OutputType.ERROR)
227
+ PrettyOutput.print(f"初始化错误: {str(e)}", OutputType.ERROR)
210
228
  return 1
211
229
 
212
230
  return 0
@@ -42,7 +42,7 @@ def _parse_file_selection(input_str: str, max_index: int) -> List[int]:
42
42
  if start <= end:
43
43
  selected.update(range(start, end + 1))
44
44
  except ValueError:
45
- PrettyOutput.print(f"Ignore invalid range expression: {part}", OutputType.WARNING)
45
+ PrettyOutput.print(f"忽略无效的范围表达式: {part}", OutputType.WARNING)
46
46
  # Process single number
47
47
  else:
48
48
  try:
@@ -50,9 +50,9 @@ def _parse_file_selection(input_str: str, max_index: int) -> List[int]:
50
50
  if 0 <= index < max_index:
51
51
  selected.add(index)
52
52
  else:
53
- PrettyOutput.print(f"Ignore index out of range: {part}", OutputType.WARNING)
53
+ PrettyOutput.print(f"忽略超出范围的索引: {part}", OutputType.WARNING)
54
54
  except ValueError:
55
- PrettyOutput.print(f"Ignore invalid number: {part}", OutputType.WARNING)
55
+ PrettyOutput.print(f"忽略无效的数字: {part}", OutputType.WARNING)
56
56
 
57
57
  return sorted(list(selected))
58
58
 
@@ -127,8 +127,8 @@ def _fuzzy_match_files(root_dir: str, pattern: str) -> List[str]:
127
127
 
128
128
  def select_files(related_files: List[Dict[str, str]], root_dir: str) -> List[Dict[str, str]]:
129
129
  """Let the user select and supplement related files"""
130
- PrettyOutput.section("Related files", OutputType.INFO)
131
-
130
+ PrettyOutput.section("相关文件", OutputType.INFO)
131
+
132
132
  output = ""
133
133
  # Display found files
134
134
  selected_files = list(related_files) # Default select all
@@ -139,18 +139,18 @@ def select_files(related_files: List[Dict[str, str]], root_dir: str) -> List[Dic
139
139
 
140
140
  if len(related_files) > 0:
141
141
  # Ask the user if they need to adjust the file list
142
- if user_confirm("Do you need to adjust the file list?", False):
142
+ if user_confirm("是否需要调整文件列表?", False):
143
143
  # Let the user select files
144
- numbers = get_single_line_input("Please enter the file numbers to include (support: 1,3-6 format, press Enter to keep the current selection)").strip()
144
+ numbers = get_single_line_input("请输入要包含的文件编号(支持: 1,3-6格式, 按回车保持当前选择)").strip()
145
145
  if numbers:
146
146
  selected_indices = _parse_file_selection(numbers, len(related_files))
147
147
  if selected_indices:
148
148
  selected_files = [related_files[i] for i in selected_indices]
149
149
  else:
150
- PrettyOutput.print("No valid files selected, keep the current selection", OutputType.WARNING)
150
+ PrettyOutput.print("没有有效的文件被选择, 保持当前选择", OutputType.WARNING)
151
151
 
152
152
  # Ask if they need to supplement files
153
- if user_confirm("Do you need to supplement other files?", False):
153
+ if user_confirm("是否需要补充其他文件?", False):
154
154
  # Create file completion session
155
155
  session = PromptSession(
156
156
  completer=_get_file_completer(root_dir),
@@ -158,7 +158,7 @@ def select_files(related_files: List[Dict[str, str]], root_dir: str) -> List[Dic
158
158
  )
159
159
 
160
160
  while True:
161
- PrettyOutput.print("Please enter the file path to supplement (support Tab completion and *? wildcard, input empty line to end):", OutputType.INFO)
161
+ PrettyOutput.print("请输入要补充的文件路径(支持Tab补全和*?通配符, 输入空行结束)", OutputType.INFO)
162
162
  try:
163
163
  file_path = session.prompt(">>> ").strip()
164
164
  except KeyboardInterrupt:
@@ -171,16 +171,16 @@ def select_files(related_files: List[Dict[str, str]], root_dir: str) -> List[Dic
171
171
  if '*' in file_path or '?' in file_path:
172
172
  matches = _fuzzy_match_files(root_dir, file_path)
173
173
  if not matches:
174
- PrettyOutput.print("No matching files found", OutputType.WARNING)
174
+ PrettyOutput.print("没有找到匹配的文件", OutputType.WARNING)
175
175
  continue
176
176
 
177
177
  # Display matching files
178
- PrettyOutput.print("Found the following matching files:", OutputType.INFO)
178
+ PrettyOutput.print("找到以下匹配的文件:", OutputType.INFO)
179
179
  for i, path in enumerate(matches, 1):
180
180
  PrettyOutput.print(f"[{i}] {path}", OutputType.INFO)
181
181
 
182
182
  # Let the user select
183
- numbers = get_single_line_input("Please select the file numbers to add (support: 1,3-6 format, press Enter to select all)").strip()
183
+ numbers = get_single_line_input("请选择要添加的文件编号(支持: 1,3-6格式, 按回车选择所有)").strip()
184
184
  if numbers:
185
185
  indices = _parse_file_selection(numbers, len(matches))
186
186
  if not indices:
@@ -195,13 +195,13 @@ def select_files(related_files: List[Dict[str, str]], root_dir: str) -> List[Dic
195
195
  for path in paths_to_add:
196
196
  full_path = os.path.join(root_dir, path)
197
197
  if not os.path.isfile(full_path):
198
- PrettyOutput.print(f"File does not exist: {path}", OutputType.ERROR)
198
+ PrettyOutput.print(f"文件不存在: {path}", OutputType.ERROR)
199
199
  continue
200
200
 
201
201
  try:
202
202
  selected_files.append({"file": path, "reason": "User Added"})
203
- PrettyOutput.print(f"File added: {path}", OutputType.SUCCESS)
203
+ PrettyOutput.print(f"文件已添加: {path}", OutputType.SUCCESS)
204
204
  except Exception as e:
205
- PrettyOutput.print(f"Failed to read file: {str(e)}", OutputType.ERROR)
205
+ PrettyOutput.print(f"读取文件失败: {str(e)}", OutputType.ERROR)
206
206
 
207
207
  return selected_files
@@ -2,13 +2,13 @@ import re
2
2
  from typing import Dict, Any, List
3
3
  import os
4
4
  from jarvis.jarvis_tools.git_commiter import GitCommitTool
5
- from jarvis.utils import OutputType, PrettyOutput, has_uncommitted_changes, user_confirm
5
+ from jarvis.utils import OutputType, PrettyOutput, get_multiline_input, has_uncommitted_changes, user_confirm
6
6
 
7
7
 
8
8
  def _parse_patch(patch_str: str) -> Dict[str, List[Dict[str, Any]]]:
9
9
  """Parse patches from string with format:
10
10
  <PATCH>
11
- > /path/to/file start_line,end_line
11
+ > path/to/file start_line,end_line
12
12
  content_line1
13
13
  content_line2
14
14
  ...
@@ -77,12 +77,12 @@ def apply_patch(output_str: str)->str:
77
77
  # Write new file
78
78
  with open(filepath, 'w', encoding='utf-8') as f:
79
79
  f.writelines(new_content)
80
- PrettyOutput.print(f"Created new file {filepath} successfully\n", OutputType.SUCCESS)
80
+ PrettyOutput.print(f"成功创建新文件 {filepath}", OutputType.SUCCESS)
81
81
  continue
82
82
 
83
83
  # Regular patch logic for existing files
84
84
  if not os.path.exists(filepath):
85
- PrettyOutput.print(f"File not found: {filepath}", OutputType.WARNING)
85
+ PrettyOutput.print(f"文件不存在: {filepath}", OutputType.WARNING)
86
86
  continue
87
87
 
88
88
  # Read original file content
@@ -90,7 +90,7 @@ def apply_patch(output_str: str)->str:
90
90
 
91
91
  # Validate line numbers
92
92
  if start_line < 0 or end_line > len(lines) + 1 or start_line > end_line:
93
- PrettyOutput.print(f"Invalid line range [{start_line}, {end_line}) for file: {filepath}", OutputType.WARNING)
93
+ PrettyOutput.print(f"无效的行范围 [{start_line}, {end_line}) 对于文件: {filepath}", OutputType.WARNING)
94
94
  continue
95
95
 
96
96
  # Create new content
@@ -99,15 +99,21 @@ def apply_patch(output_str: str)->str:
99
99
  # Write back to file
100
100
  open(filepath, 'w', encoding='utf-8').writelines(lines)
101
101
 
102
- PrettyOutput.print(f"Applied patch to {filepath} successfully\n", OutputType.SUCCESS)
102
+ PrettyOutput.print(f"成功应用补丁到 {filepath}", OutputType.SUCCESS)
103
103
 
104
104
  except Exception as e:
105
- PrettyOutput.print(f"Error applying patch to {filepath}: {str(e)}", OutputType.ERROR)
105
+ PrettyOutput.print(f"应用补丁到 {filepath} 失败: {str(e)}", OutputType.ERROR)
106
106
  continue
107
-
107
+ ret = ""
108
108
  if has_uncommitted_changes():
109
- handle_commit_workflow()
110
- return ""
109
+ if handle_commit_workflow():
110
+ ret += "Successfully applied the patch"
111
+ else:
112
+ ret += "User rejected the patch"
113
+ user_input = get_multiline_input("你可以继续输入: ")
114
+ if user_input:
115
+ ret += user_input
116
+ return ret
111
117
 
112
118
  def handle_commit_workflow()->bool:
113
119
  """Handle the git commit workflow and return the commit details.
@@ -119,7 +125,7 @@ def handle_commit_workflow()->bool:
119
125
  diff = os.popen("git diff HEAD").read()
120
126
  os.system("git reset HEAD")
121
127
  PrettyOutput.print(diff, OutputType.CODE, lang="diff")
122
- if not user_confirm("Do you want to commit the code?", default=True):
128
+ if not user_confirm("是否要提交代码?", default=True):
123
129
  os.system("git reset HEAD")
124
130
  os.system("git checkout -- .")
125
131
  os.system("git clean -fd")