jarvis-ai-assistant 0.1.207__py3-none-any.whl → 0.1.209__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 (42) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +63 -103
  3. jarvis/jarvis_agent/edit_file_handler.py +43 -47
  4. jarvis/jarvis_agent/jarvis.py +33 -39
  5. jarvis/jarvis_code_agent/code_agent.py +74 -30
  6. jarvis/jarvis_code_agent/lint.py +6 -6
  7. jarvis/jarvis_code_analysis/code_review.py +164 -175
  8. jarvis/jarvis_data/config_schema.json +0 -25
  9. jarvis/jarvis_git_utils/git_commiter.py +148 -153
  10. jarvis/jarvis_methodology/main.py +70 -81
  11. jarvis/jarvis_platform/base.py +21 -17
  12. jarvis/jarvis_platform/kimi.py +59 -64
  13. jarvis/jarvis_platform/tongyi.py +118 -131
  14. jarvis/jarvis_platform/yuanbao.py +117 -122
  15. jarvis/jarvis_platform_manager/main.py +102 -502
  16. jarvis/jarvis_platform_manager/service.py +432 -0
  17. jarvis/jarvis_smart_shell/main.py +99 -33
  18. jarvis/jarvis_tools/ask_user.py +0 -1
  19. jarvis/jarvis_tools/edit_file.py +64 -55
  20. jarvis/jarvis_tools/file_analyzer.py +17 -28
  21. jarvis/jarvis_tools/read_code.py +80 -81
  22. jarvis/jarvis_utils/builtin_replace_map.py +1 -36
  23. jarvis/jarvis_utils/config.py +13 -48
  24. jarvis/jarvis_utils/embedding.py +6 -51
  25. jarvis/jarvis_utils/git_utils.py +93 -43
  26. jarvis/jarvis_utils/http.py +104 -0
  27. jarvis/jarvis_utils/methodology.py +12 -17
  28. jarvis/jarvis_utils/utils.py +186 -63
  29. {jarvis_ai_assistant-0.1.207.dist-info → jarvis_ai_assistant-0.1.209.dist-info}/METADATA +4 -19
  30. {jarvis_ai_assistant-0.1.207.dist-info → jarvis_ai_assistant-0.1.209.dist-info}/RECORD +34 -40
  31. {jarvis_ai_assistant-0.1.207.dist-info → jarvis_ai_assistant-0.1.209.dist-info}/entry_points.txt +1 -1
  32. jarvis/jarvis_data/huggingface.tar.gz +0 -0
  33. jarvis/jarvis_dev/main.py +0 -1247
  34. jarvis/jarvis_tools/chdir.py +0 -72
  35. jarvis/jarvis_tools/code_plan.py +0 -218
  36. jarvis/jarvis_tools/create_code_agent.py +0 -95
  37. jarvis/jarvis_tools/create_sub_agent.py +0 -82
  38. jarvis/jarvis_tools/file_operation.py +0 -238
  39. jarvis/jarvis_utils/jarvis_history.py +0 -98
  40. {jarvis_ai_assistant-0.1.207.dist-info → jarvis_ai_assistant-0.1.209.dist-info}/WHEEL +0 -0
  41. {jarvis_ai_assistant-0.1.207.dist-info → jarvis_ai_assistant-0.1.209.dist-info}/licenses/LICENSE +0 -0
  42. {jarvis_ai_assistant-0.1.207.dist-info → jarvis_ai_assistant-0.1.209.dist-info}/top_level.txt +0 -0
jarvis/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Jarvis AI Assistant"""
3
3
 
4
- __version__ = "0.1.207"
4
+ __version__ = "0.1.209"
@@ -7,27 +7,30 @@ import platform
7
7
  from typing import Any, Callable, Dict, List, Optional, Protocol, Tuple, Union
8
8
 
9
9
  # 第三方库导入
10
- from yaspin import yaspin # type: ignore
11
10
 
12
11
  # 本地库导入
13
12
  # jarvis_agent 相关
14
13
  # jarvis_platform 相关
15
14
  from jarvis.jarvis_platform.base import BasePlatform
16
15
  from jarvis.jarvis_platform.registry import PlatformRegistry
16
+
17
17
  # jarvis_utils 相关
18
- from jarvis.jarvis_utils.config import (get_data_dir, get_max_token_count,
19
- get_max_tool_call_count,
20
- is_auto_complete,
21
- is_execute_tool_confirm,
22
- is_use_analysis, get_history_count, is_use_methodology)
18
+ from jarvis.jarvis_utils.config import (
19
+ get_max_token_count,
20
+ is_execute_tool_confirm,
21
+ is_use_analysis,
22
+ is_use_methodology,
23
+ )
23
24
  from jarvis.jarvis_utils.embedding import get_context_token_count
24
- from jarvis.jarvis_utils.globals import (delete_agent, get_interrupt,
25
- make_agent_name, set_agent,
26
- set_interrupt)
25
+ from jarvis.jarvis_utils.globals import (
26
+ delete_agent,
27
+ get_interrupt,
28
+ make_agent_name,
29
+ set_agent,
30
+ set_interrupt,
31
+ )
27
32
  from jarvis.jarvis_utils.input import get_multiline_input
28
- from jarvis.jarvis_utils.jarvis_history import JarvisHistory
29
- from jarvis.jarvis_utils.methodology import (load_methodology,
30
- upload_methodology)
33
+ from jarvis.jarvis_utils.methodology import load_methodology, upload_methodology
31
34
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
32
35
  from jarvis.jarvis_utils.tag import ct, ot
33
36
  from jarvis.jarvis_utils.utils import user_confirm
@@ -139,7 +142,7 @@ class Agent:
139
142
  self.prompt = ""
140
143
 
141
144
  def __del__(self):
142
- self.history.stop_record()
145
+ # 只有在记录启动时才停止记录
143
146
  delete_agent(self.name)
144
147
 
145
148
  def __init__(
@@ -150,7 +153,7 @@ class Agent:
150
153
  platform: Union[Optional[BasePlatform], Optional[str]] = None,
151
154
  model_name: Optional[str] = None,
152
155
  summary_prompt: Optional[str] = None,
153
- auto_complete: Optional[bool] = None,
156
+ auto_complete: bool = False,
154
157
  output_handler: List[OutputHandlerProtocol] = [],
155
158
  use_tools: List[str] = [],
156
159
  input_handler: Optional[List[Callable[[str, Any], Tuple[str, bool]]]] = None,
@@ -160,7 +163,6 @@ class Agent:
160
163
  use_methodology: Optional[bool] = None,
161
164
  use_analysis: Optional[bool] = None,
162
165
  files: List[str] = [],
163
- history_count: Optional[int] = None,
164
166
  ):
165
167
  self.files = files
166
168
  """初始化Jarvis Agent实例
@@ -235,17 +237,8 @@ class Agent:
235
237
  # Load configuration from environment variables
236
238
  self.addon_prompt = ""
237
239
 
238
- self.tool_call_count = 0
239
- self.max_tool_call_count = get_max_tool_call_count()
240
240
  self.after_tool_call_cb: Optional[Callable[[Agent], None]] = None
241
241
 
242
- self.history = JarvisHistory()
243
- self.history_dir = str(Path(get_data_dir())/"history")
244
- self.history.start_record(self.history_dir)
245
-
246
- self.history_count = history_count if history_count is not None else get_history_count()
247
-
248
-
249
242
  self.execute_tool_confirm = (
250
243
  execute_tool_confirm
251
244
  if execute_tool_confirm is not None
@@ -274,9 +267,7 @@ class Agent:
274
267
  )
275
268
 
276
269
  self.max_token_count = get_max_token_count()
277
- self.auto_complete = (
278
- auto_complete if auto_complete is not None else is_auto_complete()
279
- )
270
+ self.auto_complete = auto_complete
280
271
  welcome_message = f"{name} 初始化完成 - 使用 {self.model.name()} 模型"
281
272
 
282
273
  PrettyOutput.print(welcome_message, OutputType.SYSTEM)
@@ -407,10 +398,10 @@ class Agent:
407
398
  if self.conversation_length > self.max_token_count:
408
399
  message = self._summarize_and_clear_history() + "\n\n" + message
409
400
  self.conversation_length += get_context_token_count(message)
410
- self.history.append_msg("user", message)
401
+
411
402
  response = self.model.chat_until_success(message) # type: ignore
412
403
  self.conversation_length += get_context_token_count(response)
413
- self.history.append_msg("assistant", response)
404
+
414
405
  return response
415
406
 
416
407
  def generate_summary(self) -> str:
@@ -422,8 +413,8 @@ class Agent:
422
413
  注意:
423
414
  仅生成摘要,不修改对话状态
424
415
  """
425
- with yaspin(text="正在总结对话历史...", color="cyan") as spinner:
426
- summary_prompt = """
416
+ print("📄 正在总结对话历史...")
417
+ summary_prompt = """
427
418
  <summary_request>
428
419
  <objective>
429
420
  请对当前对话历史进行简明扼要的总结,提取关键信息和重要决策点。这个总结将作为上下文继续任务,因此需要保留对后续对话至关重要的内容。
@@ -447,14 +438,11 @@ class Agent:
447
438
  """
448
439
 
449
440
  try:
450
- with spinner.hidden():
451
- summary = self.model.chat_until_success(self.prompt + "\n" + summary_prompt) # type: ignore
452
- spinner.text = "总结对话历史完成"
453
- spinner.ok("✅")
441
+ summary = self.model.chat_until_success(self.prompt + "\n" + summary_prompt) # type: ignore
442
+ print("✅ 总结对话历史完成")
454
443
  return summary
455
444
  except Exception as e:
456
- spinner.text = "总结对话历史失败"
457
- spinner.fail("❌")
445
+ print("❌ 总结对话历史失败")
458
446
  return ""
459
447
 
460
448
  def _summarize_and_clear_history(self) -> str:
@@ -482,9 +470,9 @@ class Agent:
482
470
  summary = self.generate_summary()
483
471
  else:
484
472
  import tempfile
473
+
485
474
  tmp_file = tempfile.NamedTemporaryFile(delete=False)
486
475
  tmp_file_name = tmp_file.name
487
- self.history.save_history(tmp_file_name)
488
476
  self.clear_history() # type: ignore
489
477
 
490
478
  if need_summary:
@@ -540,32 +528,16 @@ class Agent:
540
528
  )
541
529
  if len(tool_list) == 0:
542
530
  return False, ""
543
- if (
544
- self.max_tool_call_count > 0
545
- and self.tool_call_count >= self.max_tool_call_count
546
- ):
547
- if user_confirm(f"工具调用次数超过限制,是否继续执行?", True):
548
- self.reset_tool_call_count()
549
- else:
550
- return False, ""
551
- if self.execute_tool_confirm:
552
- self.reset_tool_call_count()
531
+
553
532
  if not self.execute_tool_confirm or user_confirm(
554
533
  f"需要执行{tool_list[0].name()}确认执行?", True
555
534
  ):
556
- with yaspin(
557
- text=f"正在执行{tool_list[0].name()}...", color="cyan"
558
- ) as spinner:
559
- with spinner.hidden():
560
- result = tool_list[0].handle(response, self)
561
- spinner.text = f"{tool_list[0].name()}执行完成"
562
- spinner.ok("✅")
563
- self.tool_call_count += 1
564
- return result
565
- return False, ""
535
+ print(f"🔧 正在执行{tool_list[0].name()}...")
536
+ result = tool_list[0].handle(response, self)
537
+ print(f"✅ {tool_list[0].name()}执行完成")
566
538
 
567
- def reset_tool_call_count(self):
568
- self.tool_call_count = 0
539
+ return result
540
+ return False, ""
569
541
 
570
542
  def _complete_task(self) -> str:
571
543
  """完成任务并生成总结(如果需要)
@@ -581,21 +553,19 @@ class Agent:
581
553
  if self.use_analysis:
582
554
  self._analysis_task()
583
555
  if self.need_summary:
584
- with yaspin(text="正在生成总结...", color="cyan") as spinner:
585
- self.prompt = self.summary_prompt
586
- with spinner.hidden():
587
- ret = self.model.chat_until_success(self.prompt) # type: ignore
588
- spinner.text = "总结生成完成"
589
- spinner.ok("✅")
590
- return ret
556
+ print("📄 正在生成总结...")
557
+ self.prompt = self.summary_prompt
558
+ ret = self.model.chat_until_success(self.prompt) # type: ignore
559
+ print("✅ 总结生成完成")
560
+ return ret
591
561
 
592
562
  return "任务完成"
593
563
 
594
564
  def _analysis_task(self):
595
- with yaspin(text="正在分析任务...", color="cyan") as spinner:
596
- try:
597
- # 让模型判断是否需要生成方法论
598
- analysis_prompt = f"""<task_analysis>
565
+ print("🔍 正在分析任务...")
566
+ try:
567
+ # 让模型判断是否需要生成方法论
568
+ analysis_prompt = f"""<task_analysis>
599
569
  <request>
600
570
  当前任务已结束,请分析该任务的解决方案:
601
571
  1. 首先检查现有工具或方法论是否已经可以完成该任务,如果可以,直接说明即可,无需生成新内容
@@ -741,17 +711,12 @@ arguments:
741
711
  </output_requirements>
742
712
  </task_analysis>"""
743
713
 
744
- self.prompt = analysis_prompt
745
- with spinner.hidden():
746
- response = self.model.chat_until_success(self.prompt) # type: ignore
747
-
748
- with spinner.hidden():
749
- self._call_tools(response)
750
- spinner.text = "分析完成"
751
- spinner.ok("✅")
752
- except Exception as e:
753
- spinner.text = "分析失败"
754
- spinner.fail("❌")
714
+ self.prompt = analysis_prompt
715
+ response = self.model.chat_until_success(self.prompt) # type: ignore
716
+ self._call_tools(response)
717
+ print("✅ 分析完成")
718
+ except Exception as e:
719
+ print("❌ 分析失败")
755
720
 
756
721
  def make_default_addon_prompt(self, need_complete: bool) -> str:
757
722
  """生成附加提示。
@@ -808,9 +773,8 @@ arguments:
808
773
  set_agent(self.name, self)
809
774
 
810
775
  while True:
811
- history_md = ""
812
776
  if self.first:
813
- history_md = self._first_run()
777
+ self._first_run()
814
778
  try:
815
779
  current_response = self._call_model(self.prompt, True)
816
780
  self.prompt = ""
@@ -822,8 +786,13 @@ arguments:
822
786
  )
823
787
  if user_input:
824
788
  # 如果有工具调用且用户确认继续,则将干预信息和工具执行结果拼接为prompt
825
- if any(handler.can_handle(current_response) for handler in self.output_handler):
826
- if user_confirm("检测到有工具调用,是否继续处理工具调用?", True):
789
+ if any(
790
+ handler.can_handle(current_response)
791
+ for handler in self.output_handler
792
+ ):
793
+ if user_confirm(
794
+ "检测到有工具调用,是否继续处理工具调用?", True
795
+ ):
827
796
  self.prompt = f"{user_input}\n\n{current_response}"
828
797
  continue
829
798
  self.prompt += f"{user_input}"
@@ -843,8 +812,6 @@ arguments:
843
812
  if self.auto_complete and ot("!!!COMPLETE!!!") in current_response:
844
813
  return self._complete_task()
845
814
 
846
- self.reset_tool_call_count()
847
-
848
815
  # 获取用户输入
849
816
  user_input = self.multiline_inputer(
850
817
  f"{self.name}: 请输入,或输入空行来结束当前任务:"
@@ -858,8 +825,6 @@ arguments:
858
825
  return self._complete_task()
859
826
 
860
827
  except Exception as e:
861
- if history_md:
862
- os.remove(history_md)
863
828
  PrettyOutput.print(f"任务失败: {str(e)}", OutputType.ERROR)
864
829
  return f"Task failed: {str(e)}"
865
830
 
@@ -868,21 +833,15 @@ arguments:
868
833
  return f"Task failed: {str(e)}"
869
834
 
870
835
  def _first_run(self):
871
- history_md = ""
872
- if self.history_count > 0 and self.model and self.model.support_upload_files():
873
- import tempfile
874
- timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
875
- history_md = str(Path(tempfile.gettempdir())/f"{self.name}_history_{timestamp}.md")
876
- self.history.export_history_to_markdown(self.history_dir, history_md, max_files=self.history_count)
877
- self.files.append(history_md)
878
-
879
- # 如果有上传文件,先上传文件
836
+ # 如果有上传文件,先上传文件
880
837
  if self.model and self.model.support_upload_files():
881
838
  if self.use_methodology:
882
839
  if not upload_methodology(self.model, other_files=self.files):
883
840
  if self.files:
884
- PrettyOutput.print("文件上传失败,将忽略文件列表", OutputType.WARNING)
885
- # 上传失败则回退到本地加载
841
+ PrettyOutput.print(
842
+ "文件上传失败,将忽略文件列表", OutputType.WARNING
843
+ )
844
+ # 上传失败则回退到本地加载
886
845
  msg = self.prompt
887
846
  for handler in self.input_handler:
888
847
  msg, _ = handler(msg, self)
@@ -894,7 +853,9 @@ arguments:
894
853
  self.prompt = f"{self.prompt}\n\n上传的文件包含历史对话信息,可以从中获取一些经验信息。"
895
854
  elif self.files:
896
855
  if not self.model.upload_files(self.files):
897
- PrettyOutput.print("文件上传失败,将忽略文件列表", OutputType.WARNING)
856
+ PrettyOutput.print(
857
+ "文件上传失败,将忽略文件列表", OutputType.WARNING
858
+ )
898
859
  else:
899
860
  self.prompt = f"{self.prompt}\n\n上传的文件包含历史对话信息,可以从中获取一些经验信息。"
900
861
  else:
@@ -907,7 +868,6 @@ arguments:
907
868
  self.prompt = f"{self.prompt}\n\n以下是历史类似问题的执行经验,可参考:\n{load_methodology(msg, self.get_tool_registry())}"
908
869
 
909
870
  self.first = False
910
- return history_md
911
871
 
912
872
  def clear_history(self):
913
873
  """清空对话历史但保留系统提示
@@ -2,9 +2,6 @@ import os
2
2
  import re
3
3
  from typing import Any, Dict, List, Tuple
4
4
 
5
- from yaspin import yaspin # type: ignore
6
- from yaspin.core import Yaspin # type: ignore
7
-
8
5
  from jarvis.jarvis_agent.output_handler import OutputHandler
9
6
  from jarvis.jarvis_platform.registry import PlatformRegistry
10
7
  from jarvis.jarvis_utils.git_utils import revert_file
@@ -71,19 +68,19 @@ class EditFileHandler(OutputHandler):
71
68
  {"SEARCH": diff["SEARCH"], "REPLACE": diff["REPLACE"]} for diff in diffs
72
69
  ]
73
70
 
74
- with yaspin(text=f"正在处理文件 {file_path}...", color="cyan") as spinner:
75
- # 首先尝试fast_edit模式
76
- success, result = self._fast_edit(file_path, file_patches, spinner)
77
- if not success:
78
- # 如果fast_edit失败,尝试slow_edit模式
79
- success, result = EditFileHandler._slow_edit(
80
- file_path, file_patches, spinner, agent
81
- )
71
+ print(f"📝 正在处理文件 {file_path}...")
72
+ # 首先尝试fast_edit模式
73
+ success, result = self._fast_edit(file_path, file_patches)
74
+ if not success:
75
+ # 如果fast_edit失败,尝试slow_edit模式
76
+ success, result = EditFileHandler._slow_edit(
77
+ file_path, file_patches, agent
78
+ )
82
79
 
83
- if success:
84
- results.append(f"✅ 文件 {file_path} 修改成功")
85
- else:
86
- results.append(f"❌ 文件 {file_path} 修改失败: {result}")
80
+ if success:
81
+ results.append(f"✅ 文件 {file_path} 修改成功")
82
+ else:
83
+ results.append(f"❌ 文件 {file_path} 修改失败: {result}")
87
84
 
88
85
  summary = "\n".join(results)
89
86
  return False, summary
@@ -153,10 +150,11 @@ class EditFileHandler(OutputHandler):
153
150
  file_path = match.group(1) or match.group(2) or match.group(3)
154
151
  diffs = []
155
152
  for diff_match in self.diff_pattern.finditer(match.group(0)):
153
+ # 完全保留原始格式(包括所有空白和换行)
156
154
  diffs.append(
157
155
  {
158
- "SEARCH": diff_match.group(1).strip(),
159
- "REPLACE": diff_match.group(2).strip(),
156
+ "SEARCH": diff_match.group(1), # 原始SEARCH内容
157
+ "REPLACE": diff_match.group(2), # 原始REPLACE内容
160
158
  }
161
159
  )
162
160
  if diffs:
@@ -167,9 +165,7 @@ class EditFileHandler(OutputHandler):
167
165
  return patches
168
166
 
169
167
  @staticmethod
170
- def _fast_edit(
171
- file_path: str, patches: List[Dict[str, str]], spinner: Yaspin
172
- ) -> Tuple[bool, str]:
168
+ def _fast_edit(file_path: str, patches: List[Dict[str, str]]) -> Tuple[bool, str]:
173
169
  """快速应用补丁到文件
174
170
 
175
171
  该方法直接尝试将补丁应用到目标文件,适用于简单、明确的修改场景。
@@ -182,7 +178,6 @@ class EditFileHandler(OutputHandler):
182
178
  Args:
183
179
  file_path: 要修改的文件路径,支持绝对路径和相对路径
184
180
  patches: 补丁列表,每个补丁包含search(搜索文本)和replace(替换文本)
185
- spinner: 进度显示对象,用于显示处理状态和结果
186
181
 
187
182
  Returns:
188
183
  Tuple[bool, str]:
@@ -207,17 +202,22 @@ class EditFileHandler(OutputHandler):
207
202
  replace_text = patch["REPLACE"]
208
203
  patch_count += 1
209
204
 
210
- if search_text in modified_content:
211
- if modified_content.count(search_text) > 1:
205
+ # 精确匹配搜索文本(保留原始换行和空格)
206
+ exact_search = search_text
207
+
208
+ if exact_search in modified_content:
209
+ if modified_content.count(exact_search) > 1:
212
210
  PrettyOutput.print(
213
- f"搜索文本在文件中存在多处匹配:\n{search_text}",
211
+ f"搜索文本在文件中存在多处匹配:\n{exact_search}",
214
212
  output_type=OutputType.WARNING,
215
213
  )
216
- return False, f"搜索文本在文件中存在多处匹配:\n{search_text}"
214
+ return False, f"搜索文本在文件中存在多处匹配:\n{exact_search}"
215
+
216
+ # 直接执行替换(保留所有原始格式)
217
217
  modified_content = modified_content.replace(
218
- search_text, replace_text
218
+ exact_search, replace_text
219
219
  )
220
- spinner.write(f"✅ 补丁 #{patch_count} 应用成功")
220
+ print(f"✅ 补丁 #{patch_count} 应用成功")
221
221
  else:
222
222
  # 尝试增加缩进重试
223
223
  found = False
@@ -243,7 +243,7 @@ class EditFileHandler(OutputHandler):
243
243
  modified_content = modified_content.replace(
244
244
  indented_search, indented_replace
245
245
  )
246
- spinner.write(
246
+ print(
247
247
  f"✅ 补丁 #{patch_count} 应用成功 (自动增加 {space_count} 个空格缩进)"
248
248
  )
249
249
  found = True
@@ -260,19 +260,17 @@ class EditFileHandler(OutputHandler):
260
260
  with open(file_path, "w", encoding="utf-8") as f:
261
261
  f.write(modified_content)
262
262
 
263
- spinner.text = f"文件 {file_path} 修改完成,应用了 {patch_count} 个补丁"
264
- spinner.ok("✅")
263
+ print(f"文件 {file_path} 修改完成,应用了 {patch_count} 个补丁")
265
264
  return True, modified_content
266
265
 
267
266
  except Exception as e:
268
- spinner.text = f"文件修改失败: {str(e)}"
269
- spinner.fail("❌")
267
+ print(f"文件修改失败: {str(e)}")
270
268
  revert_file(file_path)
271
269
  return False, f"文件修改失败: {str(e)}"
272
270
 
273
271
  @staticmethod
274
272
  def _slow_edit(
275
- file_path: str, patches: List[Dict[str, str]], spinner: Yaspin, agent: Any
273
+ file_path: str, patches: List[Dict[str, str]], agent: Any
276
274
  ) -> Tuple[bool, str]:
277
275
  """使用AI模型生成补丁并应用到文件
278
276
 
@@ -287,7 +285,6 @@ class EditFileHandler(OutputHandler):
287
285
  Args:
288
286
  file_path: 要修改的文件路径,支持绝对路径和相对路径
289
287
  patches: 补丁列表,每个补丁包含search(搜索文本)和replace(替换文本)
290
- spinner: 进度显示对象,用于显示处理状态和结果
291
288
  agent: 执行处理的agent实例,用于访问AI模型平台
292
289
 
293
290
  Returns:
@@ -308,15 +305,14 @@ class EditFileHandler(OutputHandler):
308
305
  upload_success = False
309
306
 
310
307
  # 如果是大文件,尝试上传到模型平台
311
- with spinner.hidden():
312
- if (
313
- is_large_context
314
- and model.support_upload_files()
315
- and model.upload_files([file_path])
316
- ):
317
- upload_success = True
308
+ if (
309
+ is_large_context
310
+ and model.support_upload_files()
311
+ and model.upload_files([file_path])
312
+ ):
313
+ upload_success = True
318
314
 
319
- model.set_suppress_output(True)
315
+ model.set_suppress_output(False)
320
316
 
321
317
  # 构建补丁内容
322
318
  patch_content = []
@@ -387,8 +383,9 @@ class EditFileHandler(OutputHandler):
387
383
  # 检查是否被中断
388
384
  if get_interrupt():
389
385
  set_interrupt(False)
390
- with spinner.hidden():
391
- user_input = agent.multiline_inputer("补丁应用被中断,请输入补充信息:")
386
+ user_input = agent.multiline_inputer(
387
+ "补丁应用被中断,请输入补充信息:"
388
+ )
392
389
  if not user_input.strip():
393
390
  return False, "用户中断了补丁应用"
394
391
  return False, f"用户中断了补丁应用并提供了补充信息: {user_input}"
@@ -422,7 +419,7 @@ class EditFileHandler(OutputHandler):
422
419
  if generated_patches:
423
420
  # 尝试应用生成的补丁
424
421
  success, result = EditFileHandler._fast_edit(
425
- file_path, generated_patches, spinner
422
+ file_path, generated_patches
426
423
  )
427
424
  if success:
428
425
  return True, result
@@ -430,7 +427,6 @@ class EditFileHandler(OutputHandler):
430
427
  return False, "AI模型无法生成有效的补丁"
431
428
 
432
429
  except Exception as e:
433
- spinner.text = f"文件修改失败: {str(e)}"
434
- spinner.fail("❌")
430
+ print(f"文件修改失败: {str(e)}")
435
431
  revert_file(file_path)
436
432
  return False, f"文件修改失败: {str(e)}"
@@ -4,13 +4,17 @@ import os
4
4
  import sys
5
5
  from typing import Dict
6
6
 
7
- import yaml
8
- from prompt_toolkit import prompt
9
- from yaspin import yaspin
10
-
11
- from jarvis.jarvis_agent import (Agent, OutputType, PrettyOutput,
12
- get_multiline_input,
13
- origin_agent_system_prompt, user_confirm)
7
+ import yaml # type: ignore
8
+ from prompt_toolkit import prompt # type: ignore
9
+
10
+ from jarvis.jarvis_agent import (
11
+ Agent,
12
+ OutputType,
13
+ PrettyOutput,
14
+ get_multiline_input,
15
+ origin_agent_system_prompt,
16
+ user_confirm,
17
+ )
14
18
  from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
15
19
  from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
16
20
  from jarvis.jarvis_tools.registry import ToolRegistry
@@ -26,43 +30,33 @@ def _load_tasks() -> Dict[str, str]:
26
30
  data_dir = get_data_dir()
27
31
  pre_command_path = os.path.join(data_dir, "pre-command")
28
32
  if os.path.exists(pre_command_path):
29
- spinner_text = f"从{pre_command_path}加载预定义任务..."
30
- with yaspin(text=spinner_text, color="cyan") as spinner:
31
- try:
32
- with open(
33
- pre_command_path, "r", encoding="utf-8", errors="ignore"
34
- ) as f:
35
- user_tasks = yaml.safe_load(f)
36
- if isinstance(user_tasks, dict):
37
- for name, desc in user_tasks.items():
38
- if desc:
39
- tasks[str(name)] = str(desc)
40
- spinner.text = f"预定义任务加载完成{pre_command_path}"
41
- spinner.ok("✅")
42
- except (yaml.YAMLError, OSError):
43
- spinner.text = f"预定义任务加载失败{pre_command_path}"
44
- spinner.fail("❌")
33
+ print(f"🔍 从{pre_command_path}加载预定义任务...")
34
+ try:
35
+ with open(pre_command_path, "r", encoding="utf-8", errors="ignore") as f:
36
+ user_tasks = yaml.safe_load(f)
37
+ if isinstance(user_tasks, dict):
38
+ for name, desc in user_tasks.items():
39
+ if desc:
40
+ tasks[str(name)] = str(desc)
41
+ print(f"✅ 预定义任务加载完成 {pre_command_path}")
42
+ except (yaml.YAMLError, OSError):
43
+ print(f"❌ 预定义任务加载失败 {pre_command_path}")
45
44
 
46
45
  # Check .jarvis/pre-command in current directory
47
46
  pre_command_path = ".jarvis/pre-command"
48
47
  if os.path.exists(pre_command_path):
49
48
  abs_path = os.path.abspath(pre_command_path)
50
- spinner_text = f"从{abs_path}加载预定义任务..."
51
- with yaspin(text=spinner_text, color="cyan") as spinner:
52
- try:
53
- with open(
54
- pre_command_path, "r", encoding="utf-8", errors="ignore"
55
- ) as f:
56
- local_tasks = yaml.safe_load(f)
57
- if isinstance(local_tasks, dict):
58
- for name, desc in local_tasks.items():
59
- if desc:
60
- tasks[str(name)] = str(desc)
61
- spinner.text = f"预定义任务加载完成{pre_command_path}"
62
- spinner.ok("✅")
63
- except (yaml.YAMLError, OSError):
64
- spinner.text = f"预定义任务加载失败{pre_command_path}"
65
- spinner.fail("❌")
49
+ print(f"🔍 从{abs_path}加载预定义任务...")
50
+ try:
51
+ with open(pre_command_path, "r", encoding="utf-8", errors="ignore") as f:
52
+ local_tasks = yaml.safe_load(f)
53
+ if isinstance(local_tasks, dict):
54
+ for name, desc in local_tasks.items():
55
+ if desc:
56
+ tasks[str(name)] = str(desc)
57
+ print(f"✅ 预定义任务加载完成 {pre_command_path}")
58
+ except (yaml.YAMLError, OSError):
59
+ print(f"❌ 预定义任务加载失败 {pre_command_path}")
66
60
 
67
61
  return tasks
68
62