jarvis-ai-assistant 0.1.119__tar.gz → 0.1.121__tar.gz

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 (72) hide show
  1. {jarvis_ai_assistant-0.1.119/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.1.121}/PKG-INFO +1 -1
  2. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/pyproject.toml +1 -1
  3. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/setup.py +1 -1
  4. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/__init__.py +1 -1
  5. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_agent/__init__.py +3 -3
  6. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_code_agent/file_select.py +3 -3
  7. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_code_agent/patch.py +74 -34
  8. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_codebase/main.py +2 -2
  9. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_lsp/registry.py +7 -7
  10. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_platform/ai8.py +10 -10
  11. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_platform/base.py +15 -2
  12. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_platform/kimi.py +3 -3
  13. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_platform/oyi.py +11 -11
  14. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_platform/registry.py +3 -3
  15. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_platform_manager/main.py +2 -2
  16. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/ask_codebase.py +1 -1
  17. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/code_review.py +1 -1
  18. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/create_code_agent.py +1 -1
  19. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/git_commiter.py +26 -7
  20. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/rag.py +1 -1
  21. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_utils/__init__.py +120 -47
  22. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121/src/jarvis_ai_assistant.egg-info}/PKG-INFO +1 -1
  23. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/LICENSE +0 -0
  24. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/MANIFEST.in +0 -0
  25. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/README.md +0 -0
  26. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/setup.cfg +0 -0
  27. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_agent/output_handler.py +0 -0
  28. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_code_agent/__init__.py +0 -0
  29. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_code_agent/code_agent.py +0 -0
  30. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_code_agent/relevant_files.py +0 -0
  31. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_codebase/__init__.py +0 -0
  32. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_dev/main.py +0 -0
  33. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_lsp/base.py +0 -0
  34. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_lsp/cpp.py +0 -0
  35. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_lsp/go.py +0 -0
  36. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_lsp/python.py +0 -0
  37. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_lsp/rust.py +0 -0
  38. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_multi_agent/__init__.py +0 -0
  39. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_platform/__init__.py +0 -0
  40. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_platform/ollama.py +0 -0
  41. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_platform/openai.py +0 -0
  42. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_platform_manager/__init__.py +0 -0
  43. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_platform_manager/openai_test.py +0 -0
  44. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_rag/__init__.py +0 -0
  45. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_rag/main.py +0 -0
  46. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_smart_shell/__init__.py +0 -0
  47. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_smart_shell/main.py +0 -0
  48. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/__init__.py +0 -0
  49. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/ask_user.py +0 -0
  50. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/base.py +0 -0
  51. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/chdir.py +0 -0
  52. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/create_sub_agent.py +0 -0
  53. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/execute_shell.py +0 -0
  54. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/file_operation.py +0 -0
  55. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/lsp_find_definition.py +0 -0
  56. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/lsp_find_references.py +0 -0
  57. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/lsp_get_diagnostics.py +0 -0
  58. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/lsp_get_document_symbols.py +0 -0
  59. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/lsp_prepare_rename.py +0 -0
  60. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/lsp_validate_edit.py +0 -0
  61. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/methodology.py +0 -0
  62. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/read_code.py +0 -0
  63. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/read_webpage.py +0 -0
  64. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/registry.py +0 -0
  65. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/search.py +0 -0
  66. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/select_code_files.py +0 -0
  67. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis/jarvis_tools/tool_generator.py +0 -0
  68. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis_ai_assistant.egg-info/SOURCES.txt +0 -0
  69. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis_ai_assistant.egg-info/dependency_links.txt +0 -0
  70. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis_ai_assistant.egg-info/entry_points.txt +0 -0
  71. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis_ai_assistant.egg-info/requires.txt +0 -0
  72. {jarvis_ai_assistant-0.1.119 → jarvis_ai_assistant-0.1.121}/src/jarvis_ai_assistant.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.1.119
3
+ Version: 0.1.121
4
4
  Summary: Jarvis: An AI assistant that uses tools to interact with the system
5
5
  Home-page: https://github.com/skyfireitdiy/Jarvis
6
6
  Author: skyfire
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "jarvis-ai-assistant"
7
- version = "0.1.119"
7
+ version = "0.1.121"
8
8
  description = "Jarvis: An AI assistant that uses tools to interact with the system"
9
9
  readme = "README.md"
10
10
  authors = [{ name = "Your Name", email = "your.email@example.com" }]
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="jarvis-ai-assistant",
5
- version="0.1.119",
5
+ version="0.1.121",
6
6
  author="skyfire",
7
7
  author_email="skyfireitdiy@hotmail.com",
8
8
  description="An AI assistant that uses various tools to interact with the system",
@@ -1,3 +1,3 @@
1
1
  """Jarvis AI Assistant"""
2
2
 
3
- __version__ = "0.1.119"
3
+ __version__ = "0.1.121"
@@ -222,7 +222,7 @@ Please continue the task based on the above information.
222
222
  if handler.can_handle(response):
223
223
  tool_list.append(handler)
224
224
  if len(tool_list) > 1:
225
- PrettyOutput.print(f"操作失败:检测到多个操作。一次只能执行一个操作。尝试执行的操作:{', '.join([handler.name() for handler in tool_list])}", OutputType.ERROR)
225
+ PrettyOutput.print(f"操作失败:检测到多个操作。一次只能执行一个操作。尝试执行的操作:{', '.join([handler.name() for handler in tool_list])}", OutputType.WARNING)
226
226
  return False, f"Action failed: Multiple actions detected. Please only perform one action at a time. Actions attempted: {', '.join([handler.name() for handler in tool_list])}"
227
227
  if len(tool_list) == 0:
228
228
  return False, ""
@@ -376,7 +376,7 @@ def _load_tasks() -> dict:
376
376
  if desc: # Ensure description is not empty
377
377
  tasks[str(name)] = str(desc)
378
378
  else:
379
- PrettyOutput.print("警告: ~/.jarvis/pre-command 文件应该包含一个字典,键为任务名称,值为任务描述", OutputType.ERROR)
379
+ PrettyOutput.print("警告: ~/.jarvis/pre-command 文件应该包含一个字典,键为任务名称,值为任务描述", OutputType.WARNING)
380
380
  except Exception as e:
381
381
  PrettyOutput.print(f"加载 ~/.jarvis/pre-command 文件失败: {str(e)}", OutputType.ERROR)
382
382
 
@@ -392,7 +392,7 @@ def _load_tasks() -> dict:
392
392
  if desc: # Ensure description is not empty
393
393
  tasks[str(name)] = str(desc)
394
394
  else:
395
- PrettyOutput.print("警告: .jarvis/pre-command 文件应该包含一个字典,键为任务名称,值为任务描述", OutputType.ERROR)
395
+ PrettyOutput.print("警告: .jarvis/pre-command 文件应该包含一个字典,键为任务名称,值为任务描述", OutputType.WARNING)
396
396
  except Exception as e:
397
397
  PrettyOutput.print(f"加载 .jarvis/pre-command 文件失败: {str(e)}", OutputType.ERROR)
398
398
 
@@ -231,7 +231,7 @@ def file_input_handler(user_input: str, agent: Any) -> str:
231
231
  file_refs = re.findall(r'`([^`]+)`', user_input)
232
232
 
233
233
  for ref in file_refs:
234
- # Handle file:start,end format
234
+ # Handle file:start,end or file:start:end format
235
235
  if ':' in ref:
236
236
  file_path, line_range = ref.split(':', 1)
237
237
  # Initialize with default values
@@ -239,9 +239,9 @@ def file_input_handler(user_input: str, agent: Any) -> str:
239
239
  end_line = -1
240
240
 
241
241
  # Process line range if specified
242
- if ',' in line_range:
242
+ if ',' in line_range or ':' in line_range:
243
243
  try:
244
- raw_start, raw_end = map(int, line_range.split(','))
244
+ raw_start, raw_end = map(int, re.split(r'[,:]', line_range))
245
245
 
246
246
  # Handle special values and Python-style negative indices
247
247
  with open(file_path, 'r', encoding='utf-8') as f:
@@ -21,23 +21,20 @@ class PatchOutputHandler(OutputHandler):
21
21
 
22
22
  def prompt(self) -> str:
23
23
  return """
24
- # 📝 Code Modification Format
25
- Use specific blocks for different operations:
26
-
27
24
  # 🔄 REPLACE: Modify existing code
28
25
  <REPLACE>
29
26
  File: path/to/file
30
27
  Lines: [start,end] or [start,end)
31
- -----
32
- new_content
28
+ [new content]
29
+ ...
33
30
  </REPLACE>
34
31
 
35
32
  # ➕ INSERT: Add new code
36
33
  <INSERT>
37
34
  File: path/to/file
38
35
  Line: position
39
- -----
40
- new_content
36
+ [new content]
37
+ ...
41
38
  </INSERT>
42
39
 
43
40
  # 🗑️ DELETE: Remove existing code
@@ -49,8 +46,8 @@ Lines: [start,end] or [start,end)
49
46
  # 🆕 NEW_FILE: Create new file
50
47
  <NEW_FILE>
51
48
  File: path/to/file
52
- -----
53
- new_content
49
+ [new content]
50
+ ...
54
51
  </NEW_FILE>
55
52
 
56
53
  # ➡️ MOVE_FILE: Relocate a file
@@ -77,7 +74,6 @@ File: path/to/file
77
74
  - Omit for NEW_FILE/REMOVE_FILE
78
75
 
79
76
  3. Content
80
- - Use "-----" separator
81
77
  - Maintain original indentation
82
78
  - Follow existing code style
83
79
 
@@ -86,7 +82,6 @@ File: path/to/file
86
82
  <REPLACE>
87
83
  File: src/utils.py
88
84
  Lines: [9,13]
89
- -----
90
85
  def updated_function():
91
86
  # Replaces lines 9-13 inclusive
92
87
  return "new_implementation"
@@ -96,7 +91,6 @@ def updated_function():
96
91
  <REPLACE>
97
92
  File: src/calculator.py
98
93
  Lines: [5,8)
99
- -----
100
94
  def new_calculation():
101
95
  # Replaces lines 5-7 (excludes line 8)
102
96
  return 42
@@ -106,7 +100,6 @@ def new_calculation():
106
100
  <INSERT>
107
101
  File: src/main.py
108
102
  Line: 19
109
- -----
110
103
  # Inserted before line 19
111
104
  new_feature()
112
105
  </INSERT>
@@ -114,7 +107,6 @@ Line: 19
114
107
  ## NEW_FILE Example
115
108
  <NEW_FILE>
116
109
  File: src/new_module.py
117
- -----
118
110
  # New file creation
119
111
  def feature_entry():
120
112
  pass
@@ -146,6 +138,37 @@ File: src/obsolete.py
146
138
  6. Handle edge cases properly
147
139
  7. Include error handling
148
140
  8. Maintain code consistency
141
+
142
+ # 🚫 Invalid Format Examples
143
+ ## BAD EXAMPLE 1 - Do not use diff format
144
+ <REPLACE>
145
+ File: src/file.py
146
+ Lines: [5,8)
147
+ - old_line_1
148
+ + new_line_1
149
+ </REPLACE>
150
+
151
+ ## BAD EXAMPLE 2 - Do not include previous and new tags
152
+ <REPLACE>
153
+ File: src/file.py
154
+ Lines: [10,12]
155
+ <PREVIOUS>
156
+ old_code
157
+ </PREVIOUS>
158
+ <NEW>
159
+ new_code
160
+ </NEW>
161
+ </REPLACE>
162
+
163
+ ## BAD EXAMPLE 3 - Do not use comment to explain
164
+ <REPLACE>
165
+ File: src/file.py
166
+ Lines: [15,18]
167
+ # Replace the following code
168
+ old_function()
169
+ # With the new implementation
170
+ new_function()
171
+ </REPLACE>
149
172
  """
150
173
 
151
174
 
@@ -172,13 +195,13 @@ def _parse_patch(patch_str: str) -> Dict[str, List[Dict[str, Any]]]:
172
195
  if patch_type in ['REPLACE', 'DELETE']:
173
196
  # 增强正则表达式兼容性
174
197
  line_match = re.match(
175
- r"^Lines:\s*\[\s*(\d+)\s*,\s*(\d+)\s*([\]\)])\s*$", # 匹配行尾
198
+ r"^Lines:\s*\[\s*(\d+)\s*(?:,\s*(\d+)\s*)?([\]\)])\s*$", # 支持单数字格式
176
199
  lines[1].strip(), # 去除前后空格
177
200
  re.IGNORECASE
178
201
  )
179
202
  if line_match:
180
203
  start_line = int(line_match.group(1))
181
- end_value = int(line_match.group(2))
204
+ end_value = int(line_match.group(2) or line_match.group(1)) # 第二个数字不存在时使用第一个
182
205
  bracket_type = line_match.group(3).strip()
183
206
 
184
207
  # 根据括号类型处理区间
@@ -204,9 +227,21 @@ def _parse_patch(patch_str: str) -> Dict[str, List[Dict[str, Any]]]:
204
227
  else:
205
228
  continue
206
229
 
207
- # Get content (after separator)
208
- separator_index = next((i for i, line in enumerate(lines) if line.strip() == "-----"), -1)
209
- content = '\n'.join(lines[separator_index + 1:]) if separator_index != -1 else ''
230
+ # Get content (after metadata)
231
+ if patch_type in ['REPLACE', 'DELETE']:
232
+ content_start = 2 # File + Lines
233
+ elif patch_type == 'INSERT':
234
+ content_start = 2 # File + Line
235
+ elif patch_type == 'NEW_FILE':
236
+ content_start = 1 # File
237
+ elif patch_type == 'MOVE_FILE':
238
+ content_start = 2 # File + NewPath
239
+ elif patch_type == 'REMOVE_FILE':
240
+ content_start = 1 # File
241
+
242
+ content_lines = lines[content_start:]
243
+ # 保留原始缩进和空行
244
+ content = '\n'.join(content_lines).rstrip('\n') + '\n' # 保留末尾换行
210
245
 
211
246
  if filepath not in result:
212
247
  result[filepath] = []
@@ -257,7 +292,8 @@ def apply_patch(output_str: str) -> str:
257
292
  continue
258
293
 
259
294
  if has_uncommitted_changes():
260
- if handle_commit_workflow():
295
+ diff = get_diff()
296
+ if handle_commit_workflow(diff):
261
297
  ret += "Successfully applied the patch\n"
262
298
  # Get modified line ranges
263
299
  modified_ranges = get_modified_line_ranges()
@@ -266,25 +302,27 @@ def apply_patch(output_str: str) -> str:
266
302
  ret += "New code:\n"
267
303
  ret += modified_code["stdout"]
268
304
  else:
269
- ret += "User rejected the patch"
270
- user_input = get_multiline_input("你可以继续输入: ")
305
+ ret += "User rejected the patch\nThis is your patch preview:\n"
306
+ ret += diff
307
+ user_input = get_multiline_input("你可以继续输入(输入空行重试,Ctrl+C退出): ")
271
308
  if user_input:
272
309
  ret += "\n" + user_input
273
310
  else:
274
- return ""
311
+ ret += "Please check the patch again"
275
312
 
276
313
  return ret # Ensure a string is always returned
277
-
278
- def handle_commit_workflow()->bool:
314
+
315
+ def get_diff()->str:
316
+ os.system("git add .")
317
+ diff = os.popen("git diff HEAD").read()
318
+ os.system("git reset HEAD")
319
+ return diff
320
+ def handle_commit_workflow(diff:str)->bool:
279
321
  """Handle the git commit workflow and return the commit details.
280
322
 
281
323
  Returns:
282
324
  tuple[bool, str, str]: (continue_execution, commit_id, commit_message)
283
325
  """
284
- os.system("git add .")
285
- diff = os.popen("git diff HEAD").read()
286
- os.system("git reset HEAD")
287
- PrettyOutput.print(diff, OutputType.CODE, lang="diff")
288
326
  if not user_confirm("是否要提交代码?", default=True):
289
327
  os.system("git reset HEAD")
290
328
  os.system("git checkout -- .")
@@ -300,7 +338,7 @@ def get_modified_line_ranges() -> Dict[str, Tuple[int, int]]:
300
338
 
301
339
  Returns:
302
340
  Dictionary mapping file paths to tuple with (start_line, end_line) ranges
303
- for modified sections. Line numbers are 0-based.
341
+ for modified sections. Line numbers are 1-based.
304
342
  """
305
343
  # Get git diff for all files
306
344
  diff_output = os.popen("git show").read()
@@ -319,13 +357,12 @@ def get_modified_line_ranges() -> Dict[str, Tuple[int, int]]:
319
357
  # Match lines like "@@ -100,5 +100,7 @@" where the + part shows new lines
320
358
  range_match = re.match(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@", line)
321
359
  if range_match and current_file:
322
- start_line = int(range_match.group(1)) - 1 # Convert to 0-based
360
+ start_line = int(range_match.group(1)) # Keep as 1-based
323
361
  line_count = int(range_match.group(2)) if range_match.group(2) else 1
324
- end_line = start_line + line_count
362
+ end_line = start_line + line_count - 1
325
363
  result[current_file] = (start_line, end_line)
326
364
 
327
365
  return result
328
-
329
366
  # New handler functions below ▼▼▼
330
367
 
331
368
  def handle_move_file(filepath: str, patch: Dict[str, Any]):
@@ -364,7 +401,10 @@ def handle_code_operation(filepath: str, patch: Dict[str, Any]):
364
401
  end_line = patch.get('end_line', 0)
365
402
  new_content = patch.get('content', '').splitlines(keepends=True)
366
403
 
367
- PrettyOutput.print(f"patch_type: {patch_type}\nstart_line: {start_line}\nend_line: {end_line}\nnew_content:\n{new_content}", OutputType.INFO)
404
+ if not new_content:
405
+ new_content = ['']
406
+
407
+ PrettyOutput.print(f"patch_type: {patch_type}\nstart_line: {start_line}\nend_line: {end_line}\nnew_content:\n{''.join(new_content)}", OutputType.INFO)
368
408
 
369
409
  if new_content and new_content[-1] and new_content[-1][-1] != '\n':
370
410
  new_content[-1] += '\n'
@@ -336,7 +336,7 @@ Content: {content}
336
336
  vectors = np.vstack(vectors)
337
337
  if len(vectors) != len(ids):
338
338
  PrettyOutput.print(f"向量数量不匹配: {len(vectors)} 个向量 vs {len(ids)} 个ID",
339
- output_type=OutputType.ERROR)
339
+ output_type=OutputType.WARNING)
340
340
  self.index = None
341
341
  return
342
342
 
@@ -441,7 +441,7 @@ Content: {content}
441
441
  output_lines.append("删除的文件:")
442
442
  output_lines.extend(f" {f}" for f in deleted_files)
443
443
 
444
- PrettyOutput.print("\n".join(output_lines), output_type=OutputType.WARNING)
444
+ PrettyOutput.print("\n".join(output_lines), output_type=OutputType.INFO)
445
445
 
446
446
  # If force is True, continue directly
447
447
  if not force:
@@ -59,8 +59,8 @@ class LSPRegistry:
59
59
 
60
60
  if missing_methods:
61
61
  PrettyOutput.print(
62
- f"LSP {lsp_class.__name__} is missing necessary methods: {', '.join(missing_methods)}",
63
- OutputType.ERROR
62
+ f"LSP {lsp_class.__name__} 缺少必要的方法: {', '.join(missing_methods)}",
63
+ OutputType.WARNING
64
64
  )
65
65
  return False
66
66
 
@@ -72,7 +72,7 @@ class LSPRegistry:
72
72
  lsp_servers = {}
73
73
 
74
74
  if not os.path.exists(directory):
75
- PrettyOutput.print(f"LSP 目录不存在: {directory}", OutputType.ERROR)
75
+ PrettyOutput.print(f"LSP 目录不存在: {directory}", OutputType.WARNING)
76
76
  return lsp_servers
77
77
 
78
78
  package_name = None
@@ -138,7 +138,7 @@ class LSPRegistry:
138
138
  def create_lsp(self, language: str) -> Optional[BaseLSP]:
139
139
  """Create LSP instance for specified language."""
140
140
  if language not in self.lsp_servers:
141
- PrettyOutput.print(f"没有找到 LSP 支持的语言: {language}", OutputType.ERROR)
141
+ PrettyOutput.print(f"没有找到 LSP 支持的语言: {language}", OutputType.WARNING)
142
142
  return None
143
143
 
144
144
  try:
@@ -186,11 +186,11 @@ def main():
186
186
  lsp = registry.create_lsp(args.language)
187
187
 
188
188
  if not lsp:
189
- PrettyOutput.print(f"没有 LSP 支持的语言: {args.language}", OutputType.ERROR)
189
+ PrettyOutput.print(f"没有 LSP 支持的语言: {args.language}", OutputType.WARNING)
190
190
  return 1
191
191
 
192
192
  if not lsp.initialize(os.path.dirname(os.path.abspath(args.file))):
193
- PrettyOutput.print("LSP 初始化失败", OutputType.ERROR)
193
+ PrettyOutput.print("LSP 初始化失败", OutputType.WARNING)
194
194
  return 1
195
195
 
196
196
  try:
@@ -208,7 +208,7 @@ def main():
208
208
 
209
209
  elif args.action in ('references', 'definition'):
210
210
  if args.line is None or args.character is None:
211
- PrettyOutput.print("需要行和字符位置用于 references/definition", OutputType.ERROR)
211
+ PrettyOutput.print("需要行和字符位置用于 references/definition", OutputType.WARNING)
212
212
  return 1
213
213
 
214
214
  if args.action == 'references':
@@ -60,12 +60,12 @@ class AI8Model(BasePlatform):
60
60
  )
61
61
 
62
62
  if response.status_code != 200:
63
- PrettyOutput.print(f"创建会话失败: {response.status_code}", OutputType.ERROR)
63
+ PrettyOutput.print(f"创建会话失败: {response.status_code}", OutputType.WARNING)
64
64
  return False
65
65
 
66
66
  data = response.json()
67
67
  if data['code'] != 0:
68
- PrettyOutput.print(f"创建会话失败: {data.get('msg', '未知错误')}", OutputType.ERROR)
68
+ PrettyOutput.print(f"创建会话失败: {data.get('msg', '未知错误')}", OutputType.WARNING)
69
69
  return False
70
70
 
71
71
  self.conversation = data['data']
@@ -93,10 +93,10 @@ class AI8Model(BasePlatform):
93
93
  self.conversation = data['data']
94
94
  return True
95
95
  else:
96
- PrettyOutput.print(f"更新会话设置失败: {data.get('msg', '未知错误')}", OutputType.ERROR)
96
+ PrettyOutput.print(f"更新会话设置失败: {data.get('msg', '未知错误')}", OutputType.WARNING)
97
97
  return False
98
98
  else:
99
- PrettyOutput.print(f"更新会话设置失败: {response.status_code}", OutputType.ERROR)
99
+ PrettyOutput.print(f"更新会话设置失败: {response.status_code}", OutputType.WARNING)
100
100
  return False
101
101
 
102
102
  except Exception as e:
@@ -162,7 +162,7 @@ class AI8Model(BasePlatform):
162
162
 
163
163
  if response.status_code != 200:
164
164
  error_msg = f"Failed to chat: {response.status_code} {response.text}"
165
- PrettyOutput.print(error_msg, OutputType.ERROR)
165
+ PrettyOutput.print(error_msg, OutputType.WARNING)
166
166
  raise Exception(error_msg)
167
167
 
168
168
  # 处理流式响应
@@ -229,11 +229,11 @@ class AI8Model(BasePlatform):
229
229
  return True
230
230
  else:
231
231
  error_msg = f"删除会话失败: {data.get('msg', '未知错误')}"
232
- PrettyOutput.print(error_msg, OutputType.ERROR)
232
+ PrettyOutput.print(error_msg, OutputType.WARNING)
233
233
  return False
234
234
  else:
235
235
  error_msg = f"删除会话请求失败: {response.status_code}"
236
- PrettyOutput.print(error_msg, OutputType.ERROR)
236
+ PrettyOutput.print(error_msg, OutputType.WARNING)
237
237
  return False
238
238
 
239
239
  except Exception as e:
@@ -265,12 +265,12 @@ class AI8Model(BasePlatform):
265
265
  )
266
266
 
267
267
  if response.status_code != 200:
268
- PrettyOutput.print(f"获取模型列表失败: {response.status_code}", OutputType.ERROR)
268
+ PrettyOutput.print(f"获取模型列表失败: {response.status_code}", OutputType.WARNING)
269
269
  return []
270
270
 
271
271
  data = response.json()
272
272
  if data['code'] != 0:
273
- PrettyOutput.print(f"获取模型列表失败: {data.get('msg', '未知错误')}", OutputType.ERROR)
273
+ PrettyOutput.print(f"获取模型列表失败: {data.get('msg', '未知错误')}", OutputType.WARNING)
274
274
  return []
275
275
 
276
276
  # 保存模型信息
@@ -309,6 +309,6 @@ class AI8Model(BasePlatform):
309
309
  return list(self.models.keys())
310
310
 
311
311
  except Exception as e:
312
- PrettyOutput.print(f"获取模型列表失败: {str(e)}", OutputType.WARNING)
312
+ PrettyOutput.print(f"获取模型列表失败: {str(e)}", OutputType.ERROR)
313
313
  return []
314
314
 
@@ -45,9 +45,22 @@ class BasePlatform(ABC):
45
45
  duration = end_time - start_time
46
46
  char_count = len(response)
47
47
 
48
+ # Calculate token count and tokens per second
49
+ try:
50
+ from jarvis.jarvis_utils import get_context_token_count
51
+ token_count = get_context_token_count(response)
52
+ tokens_per_second = token_count / duration if duration > 0 else 0
53
+ except Exception as e:
54
+ PrettyOutput.print(f"Tokenization failed: {str(e)}", OutputType.WARNING)
55
+ token_count = 0
56
+ tokens_per_second = 0
57
+
48
58
  # Print statistics
49
- PrettyOutput.print(f"对话完成 - 耗时: {duration:.2f}秒, 输出字符数: {char_count}", OutputType.INFO)
50
-
59
+ PrettyOutput.print(
60
+ f"对话完成 - 耗时: {duration:.2f}秒, 输出字符数: {char_count}, 输出Token数量: {token_count}, 每秒Token数量: {tokens_per_second:.2f}",
61
+ OutputType.INFO,
62
+ )
63
+
51
64
  # Keep original think tag handling
52
65
  response = re.sub(r'<<think>>.*?</</think>>', '', response, flags=re.DOTALL)
53
66
  return response
@@ -198,11 +198,11 @@ class KimiModel(BasePlatform):
198
198
  if self._wait_for_parse(file_info["id"]):
199
199
  uploaded_files.append(file_info)
200
200
  else:
201
- PrettyOutput.print(f"✗ 文件解析失败: {file_path}", OutputType.ERROR)
201
+ PrettyOutput.print(f"✗ 文件解析失败: {file_path}", OutputType.WARNING)
202
202
  else:
203
203
  uploaded_files.append(file_info)
204
204
  else:
205
- PrettyOutput.print(f"错误:文件上传失败: {file_path}", OutputType.ERROR)
205
+ PrettyOutput.print(f"错误:文件上传失败: {file_path}", OutputType.WARNING)
206
206
 
207
207
  except Exception as e:
208
208
  PrettyOutput.print(f"✗ 处理文件出错 {file_path}: {str(e)}", OutputType.ERROR)
@@ -375,7 +375,7 @@ class KimiModel(BasePlatform):
375
375
  self.reset()
376
376
  return True
377
377
  else:
378
- PrettyOutput.print(f"删除会话失败: HTTP {response.status_code}", OutputType.ERROR)
378
+ PrettyOutput.print(f"删除会话失败: HTTP {response.status_code}", OutputType.WARNING)
379
379
  return False
380
380
  except Exception as e:
381
381
  PrettyOutput.print(f"删除会话时发生错误: {str(e)}", OutputType.ERROR)
@@ -83,10 +83,10 @@ class OyiModel(BasePlatform):
83
83
  self.conversation = data
84
84
  return True
85
85
  else:
86
- PrettyOutput.print(f"创建会话失败: {data['message']}", OutputType.ERROR)
86
+ PrettyOutput.print(f"创建会话失败: {data['message']}", OutputType.WARNING)
87
87
  return False
88
88
  else:
89
- PrettyOutput.print(f"创建会话失败: {response.status_code}", OutputType.ERROR)
89
+ PrettyOutput.print(f"创建会话失败: {response.status_code}", OutputType.WARNING)
90
90
  return False
91
91
 
92
92
  except Exception as e:
@@ -157,13 +157,13 @@ class OyiModel(BasePlatform):
157
157
 
158
158
  if response.status_code != 200:
159
159
  error_msg = f"聊天请求失败: {response.status_code}"
160
- PrettyOutput.print(error_msg, OutputType.ERROR)
160
+ PrettyOutput.print(error_msg, OutputType.WARNING)
161
161
  raise Exception(error_msg)
162
162
 
163
163
  data = response.json()
164
164
  if data['code'] != 200 or data['type'] != 'success':
165
165
  error_msg = f"聊天失败: {data.get('message', '未知错误')}"
166
- PrettyOutput.print(error_msg, OutputType.ERROR)
166
+ PrettyOutput.print(error_msg, OutputType.WARNING)
167
167
  raise Exception(error_msg)
168
168
 
169
169
  message_id = data['result'][-1]
@@ -196,7 +196,7 @@ class OyiModel(BasePlatform):
196
196
  return full_response
197
197
  else:
198
198
  error_msg = f"获取响应失败: {response.status_code}"
199
- PrettyOutput.print(error_msg, OutputType.ERROR)
199
+ PrettyOutput.print(error_msg, OutputType.WARNING)
200
200
  raise Exception(error_msg)
201
201
  except Exception as e:
202
202
  PrettyOutput.print(f"聊天失败: {str(e)}", OutputType.ERROR)
@@ -241,11 +241,11 @@ class OyiModel(BasePlatform):
241
241
  return True
242
242
  else:
243
243
  error_msg = f"删除会话失败: {data.get('message', '未知错误')}"
244
- PrettyOutput.print(error_msg, OutputType.ERROR)
244
+ PrettyOutput.print(error_msg, OutputType.WARNING)
245
245
  return False
246
246
  else:
247
247
  error_msg = f"删除会话请求失败: {response.status_code}"
248
- PrettyOutput.print(error_msg, OutputType.ERROR)
248
+ PrettyOutput.print(error_msg, OutputType.WARNING)
249
249
  return False
250
250
 
251
251
  except Exception as e:
@@ -281,7 +281,7 @@ class OyiModel(BasePlatform):
281
281
  # 检查文件类型
282
282
  file_type = mimetypes.guess_type(file_path)[0]
283
283
  if not file_type or not file_type.startswith(('image/', 'text/', 'application/')):
284
- PrettyOutput.print(f"文件类型 {file_type} 不支持", OutputType.ERROR)
284
+ PrettyOutput.print(f"文件类型 {file_type} 不支持", OutputType.WARNING)
285
285
  continue
286
286
 
287
287
  with open(file_path, 'rb') as f:
@@ -300,10 +300,10 @@ class OyiModel(BasePlatform):
300
300
  if data.get('code') == 200:
301
301
  self.files.append(data)
302
302
  else:
303
- PrettyOutput.print(f"文件上传失败: {data.get('message')}", OutputType.ERROR)
303
+ PrettyOutput.print(f"文件上传失败: {data.get('message')}", OutputType.WARNING)
304
304
  return []
305
305
  else:
306
- PrettyOutput.print(f"文件上传失败: {response.status_code}", OutputType.ERROR)
306
+ PrettyOutput.print(f"文件上传失败: {response.status_code}", OutputType.WARNING)
307
307
  return []
308
308
 
309
309
  return self.files
@@ -335,7 +335,7 @@ class OyiModel(BasePlatform):
335
335
  )
336
336
 
337
337
  if response.status_code != 200:
338
- PrettyOutput.print(f"获取模型列表失败: {response.status_code}", OutputType.ERROR)
338
+ PrettyOutput.print(f"获取模型列表失败: {response.status_code}", OutputType.WARNING)
339
339
  return []
340
340
 
341
341
  data = response.json()
@@ -72,7 +72,7 @@ class PlatformRegistry:
72
72
  if missing_methods:
73
73
  PrettyOutput.print(
74
74
  f"平台 {platform_class.__name__} 缺少必要的方法: {', '.join(missing_methods)}",
75
- OutputType.ERROR
75
+ OutputType.WARNING
76
76
  )
77
77
  return False
78
78
 
@@ -92,7 +92,7 @@ class PlatformRegistry:
92
92
 
93
93
  # 确保目录存在
94
94
  if not os.path.exists(directory):
95
- PrettyOutput.print(f"平台目录不存在: {directory}", OutputType.ERROR)
95
+ PrettyOutput.print(f"平台目录不存在: {directory}", OutputType.WARNING)
96
96
  return platforms
97
97
 
98
98
  # 获取目录的包名
@@ -201,7 +201,7 @@ class PlatformRegistry:
201
201
  BasePlatform: Platform instance
202
202
  """
203
203
  if name not in self.platforms:
204
- PrettyOutput.print(f"未找到平台: {name}", OutputType.ERROR)
204
+ PrettyOutput.print(f"未找到平台: {name}", OutputType.WARNING)
205
205
  return None
206
206
 
207
207
  try:
@@ -55,7 +55,7 @@ def chat_with_model(platform_name: str, model_name: str):
55
55
  # Create platform instance
56
56
  platform = registry.create_platform(platform_name)
57
57
  if not platform:
58
- PrettyOutput.print(f"创建平台 {platform_name} 失败", OutputType.ERROR)
58
+ PrettyOutput.print(f"创建平台 {platform_name} 失败", OutputType.WARNING)
59
59
  return
60
60
 
61
61
  try:
@@ -108,7 +108,7 @@ def chat_with_model(platform_name: str, model_name: str):
108
108
  # Helper function for platform and model validation
109
109
  def validate_platform_model(args):
110
110
  if not args.platform or not args.model:
111
- PrettyOutput.print("请指定平台和模型。使用 'jarvis info' 查看可用平台和模型。", OutputType.ERROR)
111
+ PrettyOutput.print("请指定平台和模型。使用 'jarvis info' 查看可用平台和模型。", OutputType.WARNING)
112
112
  return False
113
113
  return True
114
114
 
@@ -89,7 +89,7 @@ def main():
89
89
  if result["success"]:
90
90
  PrettyOutput.print(result["stdout"], OutputType.INFO, lang="markdown")
91
91
  else:
92
- PrettyOutput.print(result["stderr"], OutputType.ERROR)
92
+ PrettyOutput.print(result["stderr"], OutputType.WARNING)
93
93
 
94
94
 
95
95
  if __name__ == "__main__":
@@ -241,7 +241,7 @@ def main():
241
241
  PrettyOutput.print(report, OutputType.SUCCESS, lang="yaml")
242
242
 
243
243
  else:
244
- PrettyOutput.print(result["stderr"], OutputType.ERROR)
244
+ PrettyOutput.print(result["stderr"], OutputType.WARNING)
245
245
 
246
246
  if __name__ == "__main__":
247
247
  main()
@@ -109,7 +109,7 @@ def main():
109
109
  if result["success"]:
110
110
  PrettyOutput.print(result["stdout"], OutputType.SUCCESS)
111
111
  else:
112
- PrettyOutput.print(result["stderr"], OutputType.ERROR)
112
+ PrettyOutput.print(result["stderr"], OutputType.WARNING)
113
113
 
114
114
  if __name__ == "__main__":
115
115
  main()
@@ -1,9 +1,9 @@
1
1
  import os
2
2
  import re
3
3
  import shlex
4
+ import subprocess
4
5
  from typing import Dict, Any
5
6
  import tempfile
6
-
7
7
  import yaml
8
8
  from jarvis.jarvis_platform.registry import PlatformRegistry
9
9
  from jarvis.jarvis_utils import OutputType, PrettyOutput, has_uncommitted_changes, init_env
@@ -27,7 +27,13 @@ class GitCommitTool:
27
27
  return "<<FORMAT VIOLATION>> Invalid commit message structure"
28
28
 
29
29
  def _get_last_commit_hash(self):
30
- return os.popen("git log -1 --pretty=%H").read().strip()
30
+ process = subprocess.Popen(
31
+ ["git", "log", "-1", "--pretty=%H"],
32
+ stdout=subprocess.PIPE,
33
+ stderr=subprocess.PIPE
34
+ )
35
+ stdout, _ = process.communicate()
36
+ return stdout.decode().strip()
31
37
 
32
38
  def execute(self, args: Dict) -> Dict[str, Any]:
33
39
  """Execute automatic commit process with support for multi-line messages and special characters"""
@@ -37,10 +43,19 @@ class GitCommitTool:
37
43
  return {"success": True, "stdout": "No changes to commit", "stderr": ""}
38
44
 
39
45
  PrettyOutput.print("准备添加文件到提交...", OutputType.SYSTEM)
40
- os.system("git add .")
46
+ subprocess.Popen(
47
+ ["git", "add", "."],
48
+ stdout=subprocess.DEVNULL,
49
+ stderr=subprocess.DEVNULL
50
+ ).wait()
41
51
 
42
52
  PrettyOutput.print("获取差异...", OutputType.SYSTEM)
43
- diff = os.popen("git diff --cached --exit-code").read()
53
+ process = subprocess.Popen(
54
+ ["git", "diff", "--cached", "--exit-code"],
55
+ stdout=subprocess.PIPE,
56
+ stderr=subprocess.PIPE
57
+ )
58
+ diff = process.communicate()[0].decode()
44
59
  PrettyOutput.print(diff, OutputType.CODE, lang="diff")
45
60
 
46
61
  prompt = f'''Generate commit message with the paranoia of someone who's lost production data:
@@ -69,7 +84,7 @@ YOU MUST USE EXACTLY THIS FORMAT:
69
84
 
70
85
  PrettyOutput.print("生成提交消息...", OutputType.SYSTEM)
71
86
  platform = PlatformRegistry().get_codegen_platform()
72
- # platform.set_suppress_output(True)
87
+ platform.set_suppress_output(True)
73
88
  commit_message = platform.chat_until_success(prompt)
74
89
  commit_message = self._extract_commit_message(commit_message)
75
90
 
@@ -77,9 +92,13 @@ YOU MUST USE EXACTLY THIS FORMAT:
77
92
  with tempfile.NamedTemporaryFile(mode='w', delete=True) as tmp_file:
78
93
  tmp_file.write(commit_message)
79
94
  tmp_file.flush() # 确保内容写入文件
80
- commit_cmd = f"git commit -F {tmp_file.name}"
95
+ commit_cmd = ["git", "commit", "-F", tmp_file.name]
81
96
  PrettyOutput.print("提交...", OutputType.INFO)
82
- os.system(commit_cmd)
97
+ subprocess.Popen(
98
+ commit_cmd,
99
+ stdout=subprocess.DEVNULL,
100
+ stderr=subprocess.DEVNULL
101
+ ).wait()
83
102
 
84
103
  commit_hash = self._get_last_commit_hash()
85
104
  PrettyOutput.print(f"提交哈希: {commit_hash}\n提交消息: {commit_message}", OutputType.SUCCESS)
@@ -135,7 +135,7 @@ def main():
135
135
  if result["success"]:
136
136
  PrettyOutput.print(f"{result['stdout']}", OutputType.INFO, lang="markdown")
137
137
  else:
138
- PrettyOutput.print(result["stderr"], OutputType.ERROR)
138
+ PrettyOutput.print(result["stderr"], OutputType.WARNING)
139
139
 
140
140
  if __name__ == "__main__":
141
141
  main()
@@ -23,9 +23,11 @@ import psutil
23
23
  from rich.console import Console
24
24
  from rich.theme import Theme
25
25
  from rich.panel import Panel
26
+ from rich.box import HEAVY
26
27
  from rich.text import Text
27
28
  from rich.traceback import install as install_rich_traceback
28
29
  from rich.syntax import Syntax
30
+ from rich.style import Style as RichStyle
29
31
 
30
32
  from prompt_toolkit.completion import Completer, Completion, PathCompleter
31
33
  from prompt_toolkit.document import Document
@@ -45,18 +47,18 @@ install_rich_traceback()
45
47
 
46
48
  # Create console with custom theme
47
49
  custom_theme = Theme({
48
- "info": "yellow",
49
- "warning": "yellow",
50
- "error": "red",
51
- "success": "green",
52
- "system": "cyan",
53
- "code": "green",
54
- "result": "blue",
55
- "planning": "magenta",
56
- "progress": "white",
57
- "debug": "blue",
58
- "user": "green",
59
- "tool": "yellow",
50
+ "INFO": "yellow",
51
+ "WARNING": "yellow",
52
+ "ERROR": "red",
53
+ "SUCCESS": "green",
54
+ "SYSTEM": "cyan",
55
+ "CODE": "green",
56
+ "RESULT": "blue",
57
+ "PLANNING": "magenta",
58
+ "PROGRESS": "white",
59
+ "DEBUG": "blue",
60
+ "USER": "green",
61
+ "TOOL": "yellow",
60
62
  })
61
63
 
62
64
  console = Console(theme=custom_theme)
@@ -76,7 +78,7 @@ def set_agent(agent_name: str, agent: Any):
76
78
  current_agent_name = agent_name
77
79
 
78
80
  def get_agent_list():
79
- return "[" + str(len(global_agents)) + "]" + current_agent_name if global_agents else "No Agent"
81
+ return "[" + str(len(global_agents)) + "]" + current_agent_name if global_agents else ""
80
82
 
81
83
  def delete_agent(agent_name: str):
82
84
  if agent_name in global_agents:
@@ -85,18 +87,18 @@ def delete_agent(agent_name: str):
85
87
  current_agent_name = ""
86
88
 
87
89
  class OutputType(Enum):
88
- SYSTEM = "system" # AI assistant message
89
- CODE = "code" # Code related
90
- RESULT = "result" # Tool execution result
91
- ERROR = "error" # Error information
92
- INFO = "info" # System prompt
93
- PLANNING = "planning" # Task planning
94
- PROGRESS = "progress" # Execution progress
95
- SUCCESS = "success" # Success information
96
- WARNING = "warning" # Warning information
97
- DEBUG = "debug" # Debug information
98
- USER = "user" # User input
99
- TOOL = "tool" # Tool call
90
+ SYSTEM = "SYSTEM" # AI assistant message
91
+ CODE = "CODE" # Code related
92
+ RESULT = "RESULT" # Tool execution result
93
+ ERROR = "ERROR" # Error information
94
+ INFO = "INFO" # System prompt
95
+ PLANNING = "PLANNING" # Task planning
96
+ PROGRESS = "PROGRESS" # Execution progress
97
+ SUCCESS = "SUCCESS" # Success information
98
+ WARNING = "WARNING" # Warning information
99
+ DEBUG = "DEBUG" # Debug information
100
+ USER = "USER" # User input
101
+ TOOL = "TOOL" # Tool call
100
102
 
101
103
  class PrettyOutput:
102
104
  """Pretty output using rich"""
@@ -164,18 +166,18 @@ class PrettyOutput:
164
166
  return default_lang
165
167
 
166
168
  @staticmethod
167
- def _format(text: str, output_type: OutputType, timestamp: bool = True) -> Text:
169
+ def _format(output_type: OutputType, timestamp: bool = True) -> Text:
168
170
  """Format output text using rich Text"""
169
171
  # Create rich Text object
170
172
  formatted = Text()
171
173
 
172
174
  # Add timestamp and agent info
173
175
  if timestamp:
174
- formatted.append(f"[{datetime.now().strftime('%H:%M:%S')}] ", style="white")
175
- formatted.append(f"{get_agent_list()}", style="blue")
176
+ formatted.append(f"[{datetime.now().strftime('%H:%M:%S')}][{output_type.value}]", style=output_type.value)
177
+ formatted.append(f"[{get_agent_list()}]", style="blue")
176
178
  # Add icon
177
179
  icon = PrettyOutput._ICONS.get(output_type, "")
178
- formatted.append(f"{icon} ", style=output_type.value)
180
+ formatted.append(f" {icon} ", style=output_type.value)
179
181
 
180
182
  return formatted
181
183
 
@@ -190,27 +192,88 @@ class PrettyOutput:
190
192
  lang: Language for syntax highlighting
191
193
  traceback: Whether to show traceback for errors
192
194
  """
193
- from rich.style import Style as RichStyle
195
+
194
196
 
195
197
  # Define styles for different output types
196
198
  styles = {
197
- OutputType.SYSTEM: RichStyle(color="cyan", bold=True),
198
- OutputType.CODE: RichStyle(color="green"),
199
- OutputType.RESULT: RichStyle(color="blue"),
200
- OutputType.ERROR: RichStyle(color="red", bold=True),
201
- OutputType.INFO: RichStyle(color="yellow"),
202
- OutputType.PLANNING: RichStyle(color="magenta"),
203
- OutputType.PROGRESS: RichStyle(color="white"),
204
- OutputType.SUCCESS: RichStyle(color="green", bold=True),
205
- OutputType.WARNING: RichStyle(color="yellow", bold=True),
206
- OutputType.DEBUG: RichStyle(color="blue", dim=True),
207
- OutputType.USER: RichStyle(color="green"),
208
- OutputType.TOOL: RichStyle(color="yellow", italic=True)
199
+ OutputType.SYSTEM: RichStyle(
200
+ color="bright_cyan",
201
+ italic=True,
202
+ bold=True,
203
+ ),
204
+ OutputType.CODE: RichStyle(
205
+ color="green",
206
+ italic=True,
207
+ bgcolor="#1a1a1a",
208
+ frame=True
209
+ ),
210
+ OutputType.RESULT: RichStyle(
211
+ color="bright_blue",
212
+ bold=True,
213
+ italic=True,
214
+ overline=True,
215
+ bgcolor="navy_blue"
216
+ ),
217
+ OutputType.ERROR: RichStyle(
218
+ color="red",
219
+ bold=True,
220
+ italic=True,
221
+ blink=True,
222
+ bgcolor="dark_red",
223
+ ),
224
+ OutputType.INFO: RichStyle(
225
+ color="gold1",
226
+ dim=True,
227
+ bgcolor="grey11",
228
+ italic=True
229
+ ),
230
+ OutputType.PLANNING: RichStyle(
231
+ color="purple",
232
+ italic=True,
233
+ bold=True,
234
+ ),
235
+ OutputType.PROGRESS: RichStyle(
236
+ color="white",
237
+ encircle=True,
238
+ italic=True,
239
+ ),
240
+ OutputType.SUCCESS: RichStyle(
241
+ color="bright_green",
242
+ bold=True,
243
+ strike=False,
244
+ meta={"icon": "✓"},
245
+ italic=True
246
+ ),
247
+ OutputType.WARNING: RichStyle(
248
+ color="yellow",
249
+ bold=True,
250
+ blink2=True,
251
+ bgcolor="dark_orange",
252
+ italic=True
253
+ ),
254
+ OutputType.DEBUG: RichStyle(
255
+ color="grey58",
256
+ dim=True,
257
+ italic=True,
258
+ conceal=True
259
+ ),
260
+ OutputType.USER: RichStyle(
261
+ color="spring_green2",
262
+ reverse=True,
263
+ frame=True,
264
+ italic=True
265
+ ),
266
+ OutputType.TOOL: RichStyle(
267
+ color="dark_sea_green4",
268
+ italic=True,
269
+ bgcolor="grey19",
270
+ overline=True
271
+ )
209
272
  }
210
273
 
211
274
  # Get formatted header
212
275
  lang = lang if lang is not None else PrettyOutput._detect_language(text, default_lang='markdown')
213
- header = PrettyOutput._format("", output_type, timestamp)
276
+ header = PrettyOutput._format(output_type, timestamp)
214
277
 
215
278
  # Create syntax highlighted content
216
279
  content = Syntax(
@@ -218,7 +281,6 @@ class PrettyOutput:
218
281
  lang,
219
282
  theme="monokai",
220
283
  word_wrap=True,
221
- background_color="default"
222
284
  )
223
285
 
224
286
  # Create panel with styling
@@ -229,7 +291,8 @@ class PrettyOutput:
229
291
  title=header,
230
292
  title_align="left",
231
293
  padding=(0, 0),
232
- highlight=True
294
+ highlight=True,
295
+ box=HEAVY,
233
296
  )
234
297
 
235
298
  # Print panel
@@ -253,12 +316,22 @@ class PrettyOutput:
253
316
  @staticmethod
254
317
  def print_stream(text: str):
255
318
  """Print stream output without line break"""
256
- console.print(text, style="system", end="")
319
+ # 使用进度类型样式
320
+ style = PrettyOutput._get_style(OutputType.SYSTEM)
321
+ console.print(text, style=style, end="")
257
322
 
258
323
  @staticmethod
259
324
  def print_stream_end():
260
325
  """End stream output with line break"""
261
- console.print()
326
+ # 结束符样式
327
+ end_style = PrettyOutput._get_style(OutputType.SUCCESS)
328
+ console.print("\n", style=end_style)
329
+ console.file.flush()
330
+
331
+ @staticmethod
332
+ def _get_style(output_type: OutputType) -> RichStyle:
333
+ """Get pre-defined RichStyle for output type"""
334
+ return console.get_style(output_type.value)
262
335
 
263
336
  def get_single_line_input(tip: str) -> str:
264
337
  """Get single line input, support direction key, history function, etc."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.1.119
3
+ Version: 0.1.121
4
4
  Summary: Jarvis: An AI assistant that uses tools to interact with the system
5
5
  Home-page: https://github.com/skyfireitdiy/Jarvis
6
6
  Author: skyfire