jarvis-ai-assistant 0.1.115__py3-none-any.whl → 0.1.116__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 (51) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/{agent.py → jarvis_agent/__init__.py} +35 -159
  3. jarvis/jarvis_agent/output_handler.py +23 -0
  4. jarvis/jarvis_code_agent/code_agent.py +11 -11
  5. jarvis/jarvis_code_agent/file_select.py +28 -7
  6. jarvis/jarvis_code_agent/patch.py +25 -2
  7. jarvis/jarvis_code_agent/relevant_files.py +1 -1
  8. jarvis/jarvis_codebase/main.py +2 -2
  9. jarvis/jarvis_lsp/cpp.py +1 -1
  10. jarvis/jarvis_lsp/go.py +1 -1
  11. jarvis/jarvis_lsp/registry.py +1 -1
  12. jarvis/jarvis_lsp/rust.py +1 -1
  13. jarvis/jarvis_multi_agent/__init__.py +147 -0
  14. jarvis/jarvis_platform/ai8.py +2 -2
  15. jarvis/jarvis_platform/base.py +14 -4
  16. jarvis/jarvis_platform/kimi.py +2 -2
  17. jarvis/jarvis_platform/ollama.py +1 -1
  18. jarvis/jarvis_platform/openai.py +1 -1
  19. jarvis/jarvis_platform/oyi.py +1 -1
  20. jarvis/jarvis_platform/registry.py +1 -1
  21. jarvis/jarvis_platform_manager/main.py +422 -6
  22. jarvis/jarvis_platform_manager/openai_test.py +139 -0
  23. jarvis/jarvis_rag/main.py +2 -2
  24. jarvis/jarvis_smart_shell/main.py +17 -16
  25. jarvis/jarvis_tools/ask_codebase.py +1 -1
  26. jarvis/jarvis_tools/ask_user.py +1 -1
  27. jarvis/jarvis_tools/chdir.py +1 -1
  28. jarvis/jarvis_tools/code_review.py +3 -3
  29. jarvis/jarvis_tools/create_code_agent.py +1 -1
  30. jarvis/jarvis_tools/create_sub_agent.py +2 -2
  31. jarvis/jarvis_tools/execute_shell.py +1 -1
  32. jarvis/jarvis_tools/file_operation.py +16 -14
  33. jarvis/jarvis_tools/git_commiter.py +2 -2
  34. jarvis/jarvis_tools/methodology.py +1 -1
  35. jarvis/jarvis_tools/rag.py +1 -1
  36. jarvis/jarvis_tools/read_code.py +19 -8
  37. jarvis/jarvis_tools/read_webpage.py +1 -1
  38. jarvis/jarvis_tools/registry.py +53 -6
  39. jarvis/jarvis_tools/search.py +1 -1
  40. jarvis/jarvis_tools/select_code_files.py +1 -1
  41. jarvis/{utils.py → jarvis_utils/__init__.py} +69 -53
  42. {jarvis_ai_assistant-0.1.115.dist-info → jarvis_ai_assistant-0.1.116.dist-info}/METADATA +1 -1
  43. jarvis_ai_assistant-0.1.116.dist-info/RECORD +64 -0
  44. {jarvis_ai_assistant-0.1.115.dist-info → jarvis_ai_assistant-0.1.116.dist-info}/WHEEL +1 -1
  45. {jarvis_ai_assistant-0.1.115.dist-info → jarvis_ai_assistant-0.1.116.dist-info}/entry_points.txt +1 -2
  46. jarvis/jarvis_dev/main.py +0 -664
  47. jarvis/multi_agent.py +0 -76
  48. jarvis/utils/date_utils.py +0 -19
  49. jarvis_ai_assistant-0.1.115.dist-info/RECORD +0 -64
  50. {jarvis_ai_assistant-0.1.115.dist-info → jarvis_ai_assistant-0.1.116.dist-info}/LICENSE +0 -0
  51. {jarvis_ai_assistant-0.1.115.dist-info → jarvis_ai_assistant-0.1.116.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  from typing import Dict, Any
2
2
  import os
3
- from jarvis.utils import PrettyOutput, OutputType
3
+ from jarvis.jarvis_utils import PrettyOutput, OutputType
4
4
 
5
5
  class ChdirTool:
6
6
  name = "chdir"
@@ -3,8 +3,8 @@ import subprocess
3
3
  import yaml
4
4
  from jarvis.jarvis_platform.registry import PlatformRegistry
5
5
  from jarvis.jarvis_tools.registry import ToolRegistry
6
- from jarvis.utils import OutputType, PrettyOutput, init_env, find_git_root
7
- from jarvis.agent import Agent
6
+ from jarvis.jarvis_utils import OutputType, PrettyOutput, init_env, find_git_root
7
+ from jarvis.jarvis_agent import Agent
8
8
  import re
9
9
 
10
10
  class CodeReviewTool:
@@ -168,7 +168,7 @@ OUTPUT REQUIREMENTS:
168
168
  suggestion: # Specific, actionable improvements for the observed code
169
169
  </REPORT>""",
170
170
  is_sub_agent=True,
171
- tool_registry=tool_registry,
171
+ output_handler=[tool_registry],
172
172
  platform=PlatformRegistry().get_thinking_platform(),
173
173
  auto_complete=True
174
174
  )
@@ -3,7 +3,7 @@ from typing import Dict, Any
3
3
  from jarvis.jarvis_code_agent.code_agent import CodeAgent
4
4
  from jarvis.jarvis_tools.git_commiter import GitCommitTool
5
5
  from jarvis.jarvis_tools.code_review import CodeReviewTool, extract_code_report
6
- from jarvis.utils import OutputType, PrettyOutput, has_uncommitted_changes
6
+ from jarvis.jarvis_utils import OutputType, PrettyOutput, has_uncommitted_changes
7
7
 
8
8
  class CreateCodeAgentTool:
9
9
  """Tool for managing the code development workflow."""
@@ -1,9 +1,9 @@
1
1
  from typing import Dict, Any
2
2
 
3
3
 
4
- from jarvis.agent import Agent, origin_agent_system_prompt
4
+ from jarvis.jarvis_agent import Agent, origin_agent_system_prompt
5
5
  from jarvis.jarvis_tools.registry import ToolRegistry
6
- from jarvis.utils import OutputType, PrettyOutput
6
+ from jarvis.jarvis_utils import OutputType, PrettyOutput
7
7
 
8
8
 
9
9
  class SubAgentTool:
@@ -3,7 +3,7 @@ import os
3
3
  import tempfile
4
4
  from pathlib import Path
5
5
 
6
- from jarvis.utils import OutputType, PrettyOutput
6
+ from jarvis.jarvis_utils import OutputType, PrettyOutput
7
7
 
8
8
 
9
9
  class ShellTool:
@@ -1,7 +1,7 @@
1
1
  from typing import Dict, Any, List, Union
2
2
  import os
3
3
 
4
- from jarvis.utils import OutputType, PrettyOutput
4
+ from jarvis.jarvis_utils import OutputType, PrettyOutput
5
5
 
6
6
 
7
7
  class FileOperationTool:
@@ -38,25 +38,27 @@ class FileOperationTool:
38
38
  PrettyOutput.print(f"文件操作: {operation} - {abs_path}", OutputType.INFO)
39
39
 
40
40
  if operation == "read":
41
- if not os.path.exists(filepath):
41
+ if not os.path.exists(abs_path):
42
+ PrettyOutput.print(f"文件不存在: {abs_path}", OutputType.WARNING)
42
43
  return {
43
44
  "success": False,
44
45
  "stdout": "",
45
- "stderr": f"文件不存在: {filepath}"
46
+ "stderr": f"文件不存在: {abs_path}"
46
47
  }
47
48
 
48
- if os.path.getsize(filepath) > 10 * 1024 * 1024: # 10MB
49
+ if os.path.getsize(abs_path) > 10 * 1024 * 1024: # 10MB
50
+ PrettyOutput.print(f"文件太大: {abs_path}", OutputType.WARNING)
49
51
  return {
50
52
  "success": False,
51
53
  "stdout": "",
52
54
  "stderr": "File too large (>10MB)"
53
55
  }
54
56
 
55
- content = open(filepath, 'r', encoding='utf-8').read()
56
- output = f"File: {filepath}\n{content}"
57
+ content = open(abs_path, 'r', encoding='utf-8').read()
58
+ output = f"File: {abs_path}\n{content}"
57
59
 
58
60
  # Print file content
59
- PrettyOutput.print(f"读取文件: {filepath}\n{content}", OutputType.INFO)
61
+ PrettyOutput.print(f"读取文件: {abs_path}\n{content}", OutputType.INFO)
60
62
 
61
63
  return {
62
64
  "success": True,
@@ -65,17 +67,17 @@ class FileOperationTool:
65
67
  }
66
68
 
67
69
  elif operation == "write":
68
- os.makedirs(os.path.dirname(os.path.abspath(filepath)), exist_ok=True)
69
- with open(filepath, 'w', encoding='utf-8') as f:
70
+ os.makedirs(os.path.dirname(os.path.abspath(abs_path)), exist_ok=True)
71
+ with open(abs_path, 'w', encoding='utf-8') as f:
70
72
  f.write(content)
71
73
 
72
- PrettyOutput.print(f"写入文件: {filepath}", OutputType.INFO)
74
+ PrettyOutput.print(f"写入文件: {abs_path}", OutputType.INFO)
73
75
  return {
74
76
  "success": True,
75
- "stdout": f"Successfully wrote content to {filepath}",
77
+ "stdout": f"Successfully wrote content to {abs_path}",
76
78
  "stderr": ""
77
79
  }
78
-
80
+ PrettyOutput.print(f"未知操作: {operation}", OutputType.WARNING)
79
81
  return {
80
82
  "success": False,
81
83
  "stdout": "",
@@ -87,7 +89,7 @@ class FileOperationTool:
87
89
  return {
88
90
  "success": False,
89
91
  "stdout": "",
90
- "stderr": f"File operation failed for {filepath}: {str(e)}"
92
+ "stderr": f"File operation failed for {abs_path}: {str(e)}"
91
93
  }
92
94
 
93
95
  def execute(self, args: Dict) -> Dict[str, Any]:
@@ -120,7 +122,7 @@ class FileOperationTool:
120
122
  continue
121
123
 
122
124
  content = file_info.get("content", "") if operation == "write" else ""
123
- result = self._handle_single_file(operation, file_info["path"], content)
125
+ result = self._handle_single_file(operation, file_info["path"].strip(), content)
124
126
 
125
127
  if result["success"]:
126
128
  all_outputs.append(result["stdout"])
@@ -4,7 +4,7 @@ from typing import Dict, Any
4
4
 
5
5
  import yaml
6
6
  from jarvis.jarvis_platform.registry import PlatformRegistry
7
- from jarvis.utils import OutputType, PrettyOutput, has_uncommitted_changes, init_env
7
+ from jarvis.jarvis_utils import OutputType, PrettyOutput, has_uncommitted_changes, init_env
8
8
  import sys
9
9
 
10
10
 
@@ -53,7 +53,7 @@ class GitCommitTool:
53
53
 
54
54
  commit_hash = self._get_last_commit_hash()
55
55
 
56
- PrettyOutput.section(f"提交哈希: {commit_hash}\n提交消息: {commit_message}", OutputType.SUCCESS)
56
+ PrettyOutput.print(f"提交哈希: {commit_hash}\n提交消息: {commit_message}", OutputType.SUCCESS)
57
57
 
58
58
  return {"success": True, "stdout": yaml.safe_dump({"commit_hash": commit_hash, "commit_message": commit_message}), "stderr": ""}
59
59
 
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import yaml
3
3
  from typing import Dict, Optional, Any
4
- from jarvis.utils import OutputType, PrettyOutput, is_use_methodology
4
+ from jarvis.jarvis_utils import OutputType, PrettyOutput, is_use_methodology
5
5
 
6
6
 
7
7
  class MethodologyTool:
@@ -1,6 +1,6 @@
1
1
  from typing import Dict, Any
2
2
  import os
3
- from jarvis.utils import OutputType, PrettyOutput, dont_use_local_model
3
+ from jarvis.jarvis_utils import OutputType, PrettyOutput, dont_use_local_model
4
4
  from jarvis.jarvis_rag.main import RAGTool as RAGCore
5
5
 
6
6
  class RAGTool:
@@ -1,6 +1,6 @@
1
1
  from typing import Dict, Any, List
2
2
  import os
3
- from jarvis.utils import OutputType, PrettyOutput
3
+ from jarvis.jarvis_utils import OutputType, PrettyOutput
4
4
 
5
5
 
6
6
  class ReadCodeTool:
@@ -51,17 +51,19 @@ class ReadCodeTool:
51
51
  Dict containing operation result
52
52
  """
53
53
  try:
54
- abs_path = os.path.abspath(filepath)
54
+ abs_path = os.path.abspath(filepath.strip())
55
55
  PrettyOutput.print(f"正在读取代码文件:{abs_path}", OutputType.INFO)
56
56
 
57
- if not os.path.exists(filepath):
57
+ if not os.path.exists(abs_path):
58
+ PrettyOutput.print(f"文件不存在: {abs_path}", OutputType.WARNING)
58
59
  return {
59
60
  "success": False,
60
61
  "stdout": "",
61
- "stderr": f"File does not exist: {filepath}"
62
+ "stderr": f"File does not exist: {abs_path}"
62
63
  }
63
64
 
64
- if os.path.getsize(filepath) > 10 * 1024 * 1024: # 10MB
65
+ if os.path.getsize(abs_path) > 10 * 1024 * 1024: # 10MB
66
+ PrettyOutput.print(f"文件太大: {abs_path}", OutputType.WARNING)
65
67
  return {
66
68
  "success": False,
67
69
  "stdout": "",
@@ -69,20 +71,28 @@ class ReadCodeTool:
69
71
  }
70
72
 
71
73
  try:
72
- with open(filepath, 'r', encoding='utf-8') as f:
73
- lines = f.readlines()
74
+ lines = open(abs_path, 'r', encoding='utf-8').readlines()
74
75
  except UnicodeDecodeError:
76
+ PrettyOutput.print(f"文件解码失败: {abs_path}", OutputType.WARNING)
75
77
  return {
76
78
  "success": False,
77
79
  "stdout": "",
78
80
  "stderr": "Failed to decode file with UTF-8 encoding"
79
81
  }
82
+ except Exception as e:
83
+ PrettyOutput.print(f"读取文件失败: {abs_path}", OutputType.WARNING)
84
+ return {
85
+ "success": False,
86
+ "stdout": "",
87
+ "stderr": f"Failed to read file: {str(e)}"
88
+ }
80
89
 
81
90
  if start_line < 0:
82
91
  start_line = 0
83
92
  if end_line == -1 or end_line > len(lines):
84
93
  end_line = len(lines)
85
94
  if start_line >= end_line:
95
+ PrettyOutput.print(f"无效的行范围: [{start_line}, {end_line})", OutputType.WARNING)
86
96
  return {
87
97
  "success": False,
88
98
  "stdout": "",
@@ -96,7 +106,7 @@ class ReadCodeTool:
96
106
 
97
107
  content = "".join(formatted_lines)
98
108
  output = f"File: {filepath}\nLines: [{start_line}, {end_line})\n{content}"
99
-
109
+ PrettyOutput.print(output, OutputType.CODE)
100
110
  return {
101
111
  "success": True,
102
112
  "stdout": output,
@@ -104,6 +114,7 @@ class ReadCodeTool:
104
114
  }
105
115
 
106
116
  except Exception as e:
117
+ PrettyOutput.print(f"读取代码失败: {filepath}", OutputType.WARNING)
107
118
  return {
108
119
  "success": False,
109
120
  "stdout": "",
@@ -1,7 +1,7 @@
1
1
  from typing import Dict, Any
2
2
  import requests
3
3
  from bs4 import BeautifulSoup
4
- from jarvis.utils import PrettyOutput, OutputType
4
+ from jarvis.jarvis_utils import PrettyOutput, OutputType
5
5
 
6
6
  class WebpageTool:
7
7
  name = "read_webpage"
@@ -1,15 +1,19 @@
1
1
  import json
2
2
  from pathlib import Path
3
+ import re
3
4
  import sys
4
- from typing import Any, Callable, Dict, List, Optional
5
+ from typing import Any, Callable, Dict, List, Optional, Tuple
5
6
 
7
+ import yaml
8
+
9
+ from jarvis.jarvis_agent.output_handler import OutputHandler
6
10
  from jarvis.jarvis_platform.registry import PlatformRegistry
7
11
  from jarvis.jarvis_tools.base import Tool
8
- from jarvis.utils import OutputType, PrettyOutput, get_context_token_count, get_max_token_count
9
-
12
+ from jarvis.jarvis_utils import OutputType, PrettyOutput, get_context_token_count, get_max_token_count
10
13
 
11
- tool_call_help = """## Tool Usage Format
12
14
 
15
+ tool_call_help = """
16
+ Tool Usage Format
13
17
  <TOOL_CALL>
14
18
  name: tool_name
15
19
  arguments:
@@ -44,8 +48,17 @@ STRICT RULES:
44
48
  - If you can start executing the task, please start directly without asking the user if you can begin.
45
49
  """
46
50
 
47
- class ToolRegistry:
48
- def load_tools(self) -> str:
51
+ class ToolRegistry(OutputHandler):
52
+
53
+ def name(self) -> str:
54
+ return "TOOL_CALL"
55
+
56
+ def can_handle(self, response: str) -> bool:
57
+ if self._extract_tool_calls(response):
58
+ return True
59
+ return False
60
+
61
+ def prompt(self) -> str:
49
62
  """Load tools"""
50
63
  tools = self.get_all_tools()
51
64
  if tools:
@@ -57,6 +70,16 @@ class ToolRegistry:
57
70
  tools_prompt += tool_call_help
58
71
  return tools_prompt
59
72
  return ""
73
+
74
+ def handle(self, response: str) -> Tuple[bool, Any]:
75
+ tool_calls = self._extract_tool_calls(response)
76
+ if len(tool_calls) > 1:
77
+ PrettyOutput.print(f"操作失败:检测到多个操作。一次只能执行一个操作。尝试执行的操作:{', '.join([tool_call['name'] for tool_call in tool_calls])}", OutputType.WARNING)
78
+ return False, f"Call failed: Handle multiple tool calls, please ONLY handle one tool call at a time."
79
+ if len(tool_calls) == 0:
80
+ return False, ""
81
+ tool_call = tool_calls[0]
82
+ return False, self.handle_tool_calls(tool_call)
60
83
 
61
84
  def __init__(self):
62
85
  """Initialize tool registry"""
@@ -169,6 +192,30 @@ class ToolRegistry:
169
192
  except Exception as e:
170
193
  PrettyOutput.print(f"从 {Path(file_path).name} 加载工具失败: {str(e)}", OutputType.ERROR)
171
194
  return False
195
+ @staticmethod
196
+ def _extract_tool_calls(content: str) -> List[Dict]:
197
+ """Extract tool calls from content.
198
+
199
+ Args:
200
+ content: The content containing tool calls
201
+
202
+ Returns:
203
+ List[Dict]: List of extracted tool calls with name and arguments
204
+
205
+ Raises:
206
+ Exception: If tool call is missing necessary fields
207
+ """
208
+ # Split content into lines
209
+ data = re.findall(r'<TOOL_CALL>(.*?)</TOOL_CALL>', content, re.DOTALL)
210
+ ret = []
211
+ for item in data:
212
+ try:
213
+ msg = yaml.safe_load(item)
214
+ if 'name' in msg and 'arguments' in msg:
215
+ ret.append(msg)
216
+ except Exception as e:
217
+ continue
218
+ return ret
172
219
 
173
220
  def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
174
221
  """Register a new tool"""
@@ -1,6 +1,6 @@
1
1
  from typing import Dict, Any, List
2
2
  from jarvis.jarvis_platform.registry import PlatformRegistry
3
- from jarvis.utils import PrettyOutput, OutputType, get_context_token_count, get_max_token_count
3
+ from jarvis.jarvis_utils import PrettyOutput, OutputType, get_context_token_count, get_max_token_count
4
4
  from jarvis.jarvis_tools.read_webpage import WebpageTool
5
5
  from playwright.sync_api import sync_playwright
6
6
  from urllib.parse import quote
@@ -1,6 +1,6 @@
1
1
  from typing import Dict, Any
2
2
 
3
- from jarvis.utils import OutputType, PrettyOutput
3
+ from jarvis.jarvis_utils import OutputType, PrettyOutput
4
4
  from jarvis.jarvis_code_agent.file_select import select_files
5
5
 
6
6
 
@@ -29,7 +29,8 @@ from rich.syntax import Syntax
29
29
 
30
30
  from prompt_toolkit.completion import Completer, Completion, PathCompleter
31
31
  from prompt_toolkit.document import Document
32
- from fuzzywuzzy import fuzz
32
+ from fuzzywuzzy import process
33
+ from prompt_toolkit.key_binding import KeyBindings
33
34
 
34
35
  # 初始化colorama
35
36
  colorama.init()
@@ -271,8 +272,8 @@ class FileCompleter(Completer):
271
272
  """Custom completer for file paths with fuzzy matching."""
272
273
  def __init__(self):
273
274
  self.path_completer = PathCompleter()
274
- self.max_suggestions = 10 # 增加显示数量
275
- self.min_score = 10 # 降低相似度阈值
275
+ self.max_suggestions = 10
276
+ self.min_score = 10
276
277
 
277
278
  def get_completions(self, document: Document, complete_event):
278
279
  text = document.text_before_cursor
@@ -299,23 +300,33 @@ class FileCompleter(Completer):
299
300
  # Get the text after the current @
300
301
  file_path = text_after_at.strip()
301
302
 
302
- # Get all possible files from current directory
303
+ # 计算需要删除的字符数(包括@符号)
304
+ replace_length = len(text_after_at) + 1 # +1 包含@符号
305
+
306
+ # Get all possible files using git ls-files only
303
307
  all_files = []
304
- for root, _, files in os.walk('.'):
305
- for f in files:
306
- path = os.path.join(root, f)
307
- # Remove ./ from the beginning
308
- path = path[2:] if path.startswith('./') else path
309
- all_files.append(path)
308
+ try:
309
+ # Use git ls-files to get tracked files
310
+ import subprocess
311
+ result = subprocess.run(['git', 'ls-files'],
312
+ stdout=subprocess.PIPE,
313
+ stderr=subprocess.PIPE,
314
+ text=True)
315
+ if result.returncode == 0:
316
+ all_files = [line.strip() for line in result.stdout.splitlines() if line.strip()]
317
+ except Exception:
318
+ # If git command fails, just use an empty list
319
+ pass
310
320
 
311
321
  # If no input after @, show all files
312
322
  # Otherwise use fuzzy matching
313
323
  if not file_path:
314
324
  scored_files = [(path, 100) for path in all_files[:self.max_suggestions]]
315
325
  else:
326
+ scored_files_data = process.extract(file_path, all_files, limit=self.max_suggestions)
316
327
  scored_files = [
317
- (path, fuzz.ratio(file_path.lower(), path.lower()))
318
- for path in all_files
328
+ (m[0], m[1])
329
+ for m in scored_files_data
319
330
  ]
320
331
  # Sort by score and take top results
321
332
  scored_files.sort(key=lambda x: x[1], reverse=True)
@@ -324,66 +335,71 @@ class FileCompleter(Completer):
324
335
  # Return completions for files
325
336
  for path, score in scored_files:
326
337
  if not file_path or score > self.min_score:
327
- display_text = path
338
+ display_text = path # 显示时不带反引号
328
339
  if file_path and score < 100:
329
340
  display_text = f"{path} ({score}%)"
330
341
  completion = Completion(
331
- text=path,
332
- start_position=-len(file_path),
342
+ text=f"`{path}`", # 添加反引号包裹路径
343
+ start_position=-replace_length,
333
344
  display=display_text,
334
345
  display_meta="File"
335
346
  )
336
347
  yield completion
337
348
 
338
349
  def get_multiline_input(tip: str) -> str:
339
- """Get multi-line input, support direction key, history function, and file completion.
350
+ """Get multi-line input with enhanced completion confirmation"""
351
+ # 单行输入说明
352
+ PrettyOutput.section("用户输入 - 使用 @ 触发文件补全,Tab 选择补全项,Ctrl+J 提交", OutputType.USER)
340
353
 
341
- Args:
342
- tip: The prompt tip to display
343
-
344
- Returns:
345
- str: The entered text
346
- """
347
354
  print(f"{Fore.GREEN}{tip}{ColoramaStyle.RESET_ALL}")
348
355
 
349
- # Define prompt style
356
+ # 自定义按键绑定
357
+ bindings = KeyBindings()
358
+
359
+ @bindings.add('enter')
360
+ def _(event):
361
+ # 当有补全菜单时,回车键确认补全
362
+ if event.current_buffer.complete_state:
363
+ event.current_buffer.apply_completion(event.current_buffer.complete_state.current_completion)
364
+ else:
365
+ # 没有补全菜单时插入换行
366
+ event.current_buffer.insert_text('\n')
367
+
368
+ @bindings.add('c-j') # 修改为支持的按键组合
369
+ def _(event):
370
+ # 使用 Ctrl+J 提交输入
371
+ event.current_buffer.validate_and_handle()
372
+
350
373
  style = PromptStyle.from_dict({
351
374
  'prompt': 'ansicyan',
352
375
  })
353
-
354
- lines = []
376
+
355
377
  try:
356
- while True:
357
- # Set prompt
358
- prompt = FormattedText([
359
- ('class:prompt', '... ' if lines else '>>> ')
360
- ])
361
-
362
- # Create new session with new completer for each line
363
- session = PromptSession(
364
- history=None, # Use default history
365
- completer=FileCompleter() # New completer instance for each line
366
- )
367
-
368
- # Get input with completion support
369
- line = session.prompt(
370
- prompt,
371
- style=style,
372
- ).strip()
373
-
374
- # Handle empty line
375
- if not line:
376
- if not lines: # First line is empty
377
- return ""
378
- break # End multi-line input
379
-
380
- lines.append(line)
381
-
378
+ session = PromptSession(
379
+ history=None,
380
+ completer=FileCompleter(),
381
+ key_bindings=bindings,
382
+ complete_while_typing=True,
383
+ multiline=True, # 启用原生多行支持
384
+ vi_mode=False,
385
+ mouse_support=False
386
+ )
387
+
388
+ prompt = FormattedText([
389
+ ('class:prompt', '>>> ')
390
+ ])
391
+
392
+ # 单次获取多行输入
393
+ text = session.prompt(
394
+ prompt,
395
+ style=style,
396
+ ).strip()
397
+
398
+ return text
399
+
382
400
  except KeyboardInterrupt:
383
401
  PrettyOutput.print("输入已取消", OutputType.INFO)
384
402
  return ""
385
-
386
- return "\n".join(lines)
387
403
 
388
404
  def init_env():
389
405
  """Load environment variables from ~/.jarvis/env"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.1.115
3
+ Version: 0.1.116
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
@@ -0,0 +1,64 @@
1
+ jarvis/__init__.py,sha256=auL2YXQX-_S1mgO9Yyo0mfHN657i7dn_WX2B-daZ5gc,51
2
+ jarvis/jarvis_agent/__init__.py,sha256=949RsfwtecmezrWWU5VNCUbMZx2FXDToZBuHopEiRtc,21599
3
+ jarvis/jarvis_agent/output_handler.py,sha256=kJeFTjjSu0K_2p0wyhq2veSZuhRXoaFC_8wVaoBKX0w,401
4
+ jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ jarvis/jarvis_code_agent/code_agent.py,sha256=F7SifQk7M-M8HUf8MORFqgNI8MVZIAHPAckCgCnJHtQ,7795
6
+ jarvis/jarvis_code_agent/file_select.py,sha256=uxNA0ODy7NHMDNnCS9tFhttQ-omILUya7OjX3WuhSfo,8850
7
+ jarvis/jarvis_code_agent/patch.py,sha256=Xhaa_OOrZRC9WuDD9LvR5YPJdVekOyuiYlesIoU6ITE,5375
8
+ jarvis/jarvis_code_agent/relevant_files.py,sha256=0woLVR0umeIoi2kVCjz1gTJODEyP57Z_SzktunuitdE,3330
9
+ jarvis/jarvis_codebase/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ jarvis/jarvis_codebase/main.py,sha256=1kJ4c2qG9j0tZfUmYB-FEYr5QoAkgs4Rbr038L0usf4,39336
11
+ jarvis/jarvis_lsp/base.py,sha256=_7pdbMKjdtYBW0DsRbjIodDHM3J7df-YgXHejN_WIrU,4490
12
+ jarvis/jarvis_lsp/cpp.py,sha256=sYQHEl0FoVC5Iw2pJvvGKpeNLD95XjNuTOINvdZLgME,4986
13
+ jarvis/jarvis_lsp/go.py,sha256=3soEuID2XV65zaxyR70RxNsvtm02l9PEZ46F_nsDdqY,5311
14
+ jarvis/jarvis_lsp/python.py,sha256=_Vo2pPwVh_vAsyS0XowXMbT4Syd78naPEZj586bi004,4747
15
+ jarvis/jarvis_lsp/registry.py,sha256=x7OFlW10AWQ_tWEbHWkdpngoFHTP3t1vSyGxVVLk46w,9933
16
+ jarvis/jarvis_lsp/rust.py,sha256=ZvUoOZm9GWLl3kobfByBuTGrQ8aM2dLuNxS_NHr1aQQ,5542
17
+ jarvis/jarvis_multi_agent/__init__.py,sha256=-NY3KqwFjEcSUICXn99aiZIg7fBK9wuZo8uZhxHY45E,6087
18
+ jarvis/jarvis_platform/__init__.py,sha256=mrOt67nselz_H1gX9wdAO4y2DY5WPXzABqJbr5Des8k,63
19
+ jarvis/jarvis_platform/ai8.py,sha256=AO42OVzrwQMDY74TR2B4gtrsfeRVxJRf5OmHBM3cVQY,11948
20
+ jarvis/jarvis_platform/base.py,sha256=8iYNCe7PGSs9sDG66jeNDr2TYzWUYBiGVvKgHTDsFLg,2641
21
+ jarvis/jarvis_platform/kimi.py,sha256=WCRyG7jnqnpHNu6M9_pGFE_RBVKqYDtd_F1EPdT_FKU,15761
22
+ jarvis/jarvis_platform/ollama.py,sha256=TsBEg8crPmBiLvMRDtXYVa2AIdeog36MmW2tn5j9x8U,5613
23
+ jarvis/jarvis_platform/openai.py,sha256=rHzc20Frd5LzS0Wm97FxglSai65UKkY2ju8rg6q-gOg,4445
24
+ jarvis/jarvis_platform/oyi.py,sha256=3yuWHEGtGV--6IuFCCc1R2F1Y-p21xy4Vk-P5pQRAys,14994
25
+ jarvis/jarvis_platform/registry.py,sha256=SmBcf86h6uf4TB7cut-Bhb9Ivj5z2wAg1pWkcJLi_80,8508
26
+ jarvis/jarvis_platform_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ jarvis/jarvis_platform_manager/main.py,sha256=Ja0f-PiYxABIj-Ioh9NNZuqy0dB2Jk7dhrObgzgXApw,20958
28
+ jarvis/jarvis_platform_manager/openai_test.py,sha256=BAoZgOJ431gjjbbdgiX-ARfI0aLXK_cRLAQQJzQI6MI,5200
29
+ jarvis/jarvis_rag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ jarvis/jarvis_rag/main.py,sha256=U5h8PbVatNuZ5uFpXNV77W3TXSOGG8CrZ3huqfpPre0,31326
31
+ jarvis/jarvis_smart_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ jarvis/jarvis_smart_shell/main.py,sha256=73tSL1nCXNCPGXeLAiFq6cckv3ot5Vt5QyPkSAXhMcE,4038
33
+ jarvis/jarvis_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ jarvis/jarvis_tools/ask_codebase.py,sha256=MF7zeBqVDa7T45JxDR9mePA92kzZm5bQ9op8o5Qo9lM,3003
35
+ jarvis/jarvis_tools/ask_user.py,sha256=tIyiKk9F8xchjQ3Yh5fMQjhpflQTuh75HTuXMftGxZY,1827
36
+ jarvis/jarvis_tools/base.py,sha256=c0DMoDDPxmsqUYJR989zgUs7nIYRY6GWBrAdusIZKjc,656
37
+ jarvis/jarvis_tools/chdir.py,sha256=06GAtMqoi5fT1FXD2HUUlHKosVtz-Z8KI13lpEFQw3g,1820
38
+ jarvis/jarvis_tools/code_review.py,sha256=DFnw-li4afcpHdfDC2TX_PHSNn7GxEHbtagCAkLQ-9U,8598
39
+ jarvis/jarvis_tools/create_code_agent.py,sha256=4tJLcKk_e1AOyN2wgOeAWVB9N4aa7GsusUNdaYmAYww,3906
40
+ jarvis/jarvis_tools/create_sub_agent.py,sha256=ldpNn5LczybExvt9Sz4t1ybetLX-dTJIAF5f_oH-Z3M,2869
41
+ jarvis/jarvis_tools/execute_shell.py,sha256=MwgVyI1O1wshU9yR-DvSWIgoSQpVjtH9JpjVQvSrKF0,2566
42
+ jarvis/jarvis_tools/file_operation.py,sha256=8CAWozKfsRx_TzCmRPcNSj-bRo3K69IEDmmN8IWMlmg,5647
43
+ jarvis/jarvis_tools/git_commiter.py,sha256=oq_jh6YkB-cZi2XRhu139seZeF7Vubwx04cvpugjmt4,2732
44
+ jarvis/jarvis_tools/lsp_find_definition.py,sha256=xV8YeN1RJfwd2F3gE6OnDeTwl-AnCmrxueHocbXkQOc,4800
45
+ jarvis/jarvis_tools/lsp_find_references.py,sha256=FohlJeLfTxcMUASfbjOT93hQGtI2WeyTpMGwRwShW_I,4043
46
+ jarvis/jarvis_tools/lsp_get_diagnostics.py,sha256=bEvbDk8TnKg9TTFFxMrYOJm5TBDgz5gO04WJFQUwQQE,4490
47
+ jarvis/jarvis_tools/lsp_get_document_symbols.py,sha256=dspL6r9HYnXL5TpARSApFY3IQLm2kcYVNVWCff2xoXI,3080
48
+ jarvis/jarvis_tools/lsp_prepare_rename.py,sha256=RxUyIef4awtp-jgupcD1LcPlno9P3mOE8AS3_Fm71Ys,4832
49
+ jarvis/jarvis_tools/lsp_validate_edit.py,sha256=M0iglK2QbnIEFv0RYK6o2iAYnv259jB6EU7To-rc51E,5247
50
+ jarvis/jarvis_tools/methodology.py,sha256=JvHV6rHhC6fbPuSqC6UHFaGEE39d4g7zFLodR72wM0g,5758
51
+ jarvis/jarvis_tools/rag.py,sha256=ZhmvwVUHBFsttDRdVncc-S-a-XVOy5jbdNd7Vk4uTlk,4942
52
+ jarvis/jarvis_tools/read_code.py,sha256=rt5m-bcXY0W-WLrGgr5xG08KxB1nNGD5UD0TSj7v7lg,6826
53
+ jarvis/jarvis_tools/read_webpage.py,sha256=7QamwBi5s7lD-jTcjD0wsBvkmWPRC9-K-0JkGgeTpvs,3063
54
+ jarvis/jarvis_tools/registry.py,sha256=Kvec2iS9FPm9yScn3ef68HjtvnM98hLesdA-5jTTWec,13232
55
+ jarvis/jarvis_tools/search.py,sha256=NHrFpAqg6dtws_9wLJvIZimjeJ-kekETi0Bg0AWMG08,11437
56
+ jarvis/jarvis_tools/select_code_files.py,sha256=242K79SiNF_gY7fpThY3xoi2ihfgJdjB27X1jKkeXK0,1889
57
+ jarvis/jarvis_tools/tool_generator.py,sha256=jdniHyKcEyF9KyouudrCoZBH3czZmQXc3ns0_trZ3yU,6332
58
+ jarvis/jarvis_utils/__init__.py,sha256=2GbATVP6NXe8obg2YYArNRAeSj0X4-GCULZrMiHh3fw,29885
59
+ jarvis_ai_assistant-0.1.116.dist-info/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
60
+ jarvis_ai_assistant-0.1.116.dist-info/METADATA,sha256=JKKbhXVCkjyFGh6oo5txk5cv48exb112sNO7kWVJuwU,13701
61
+ jarvis_ai_assistant-0.1.116.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
62
+ jarvis_ai_assistant-0.1.116.dist-info/entry_points.txt,sha256=vjXpb5GC60FGbIqnVdr4hfoVzQQJLP_QRgNkkld5kPw,487
63
+ jarvis_ai_assistant-0.1.116.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
64
+ jarvis_ai_assistant-0.1.116.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (75.8.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,9 +1,8 @@
1
1
  [console_scripts]
2
- jarvis = jarvis.agent:main
2
+ jarvis = jarvis.jarvis_agent:main
3
3
  jarvis-code-agent = jarvis.jarvis_code_agent.code_agent:main
4
4
  jarvis-code-review = jarvis.jarvis_tools.code_review:main
5
5
  jarvis-codebase = jarvis.jarvis_codebase.main:main
6
- jarvis-dev = jarvis.jarvis_dev.main:main
7
6
  jarvis-git-commit = jarvis.jarvis_tools.git_commiter:main
8
7
  jarvis-platform-manager = jarvis.jarvis_platform_manager.main:main
9
8
  jarvis-rag = jarvis.jarvis_rag.main:main