jarvis-ai-assistant 0.1.123__py3-none-any.whl → 0.1.125__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of jarvis-ai-assistant might be problematic. Click here for more details.

Files changed (67) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +19 -21
  3. jarvis/jarvis_code_agent/code_agent.py +205 -119
  4. jarvis/jarvis_code_agent/file_select.py +6 -105
  5. jarvis/jarvis_code_agent/patch.py +192 -259
  6. jarvis/jarvis_codebase/main.py +6 -2
  7. jarvis/jarvis_dev/main.py +6 -4
  8. jarvis/jarvis_git_squash/__init__.py +0 -0
  9. jarvis/jarvis_git_squash/main.py +81 -0
  10. jarvis/jarvis_lsp/cpp.py +1 -1
  11. jarvis/jarvis_lsp/go.py +1 -1
  12. jarvis/jarvis_lsp/registry.py +2 -2
  13. jarvis/jarvis_lsp/rust.py +1 -1
  14. jarvis/jarvis_multi_agent/__init__.py +1 -1
  15. jarvis/jarvis_platform/ai8.py +2 -1
  16. jarvis/jarvis_platform/base.py +20 -25
  17. jarvis/jarvis_platform/kimi.py +2 -3
  18. jarvis/jarvis_platform/ollama.py +3 -1
  19. jarvis/jarvis_platform/openai.py +1 -1
  20. jarvis/jarvis_platform/oyi.py +2 -1
  21. jarvis/jarvis_platform/registry.py +2 -1
  22. jarvis/jarvis_platform_manager/main.py +4 -6
  23. jarvis/jarvis_platform_manager/openai_test.py +0 -1
  24. jarvis/jarvis_rag/main.py +5 -2
  25. jarvis/jarvis_smart_shell/main.py +9 -4
  26. jarvis/jarvis_tools/ask_codebase.py +12 -7
  27. jarvis/jarvis_tools/ask_user.py +3 -2
  28. jarvis/jarvis_tools/base.py +21 -7
  29. jarvis/jarvis_tools/chdir.py +25 -1
  30. jarvis/jarvis_tools/code_review.py +13 -14
  31. jarvis/jarvis_tools/create_code_agent.py +4 -7
  32. jarvis/jarvis_tools/create_sub_agent.py +2 -2
  33. jarvis/jarvis_tools/execute_shell.py +3 -1
  34. jarvis/jarvis_tools/execute_shell_script.py +58 -0
  35. jarvis/jarvis_tools/file_operation.py +3 -2
  36. jarvis/jarvis_tools/git_commiter.py +26 -17
  37. jarvis/jarvis_tools/lsp_find_definition.py +1 -1
  38. jarvis/jarvis_tools/lsp_find_references.py +1 -1
  39. jarvis/jarvis_tools/lsp_get_diagnostics.py +19 -11
  40. jarvis/jarvis_tools/lsp_get_document_symbols.py +1 -1
  41. jarvis/jarvis_tools/lsp_prepare_rename.py +1 -1
  42. jarvis/jarvis_tools/lsp_validate_edit.py +1 -1
  43. jarvis/jarvis_tools/methodology.py +4 -1
  44. jarvis/jarvis_tools/rag.py +22 -15
  45. jarvis/jarvis_tools/read_code.py +4 -3
  46. jarvis/jarvis_tools/read_webpage.py +2 -1
  47. jarvis/jarvis_tools/registry.py +4 -1
  48. jarvis/jarvis_tools/{search.py → search_web.py} +5 -3
  49. jarvis/jarvis_tools/select_code_files.py +1 -1
  50. jarvis/jarvis_utils/__init__.py +19 -941
  51. jarvis/jarvis_utils/config.py +138 -0
  52. jarvis/jarvis_utils/embedding.py +201 -0
  53. jarvis/jarvis_utils/git_utils.py +120 -0
  54. jarvis/jarvis_utils/globals.py +82 -0
  55. jarvis/jarvis_utils/input.py +161 -0
  56. jarvis/jarvis_utils/methodology.py +128 -0
  57. jarvis/jarvis_utils/output.py +235 -0
  58. jarvis/jarvis_utils/utils.py +150 -0
  59. jarvis_ai_assistant-0.1.125.dist-info/METADATA +291 -0
  60. jarvis_ai_assistant-0.1.125.dist-info/RECORD +75 -0
  61. {jarvis_ai_assistant-0.1.123.dist-info → jarvis_ai_assistant-0.1.125.dist-info}/WHEEL +1 -1
  62. {jarvis_ai_assistant-0.1.123.dist-info → jarvis_ai_assistant-0.1.125.dist-info}/entry_points.txt +1 -0
  63. jarvis/jarvis_code_agent/relevant_files.py +0 -117
  64. jarvis_ai_assistant-0.1.123.dist-info/METADATA +0 -461
  65. jarvis_ai_assistant-0.1.123.dist-info/RECORD +0 -65
  66. {jarvis_ai_assistant-0.1.123.dist-info → jarvis_ai_assistant-0.1.125.dist-info}/LICENSE +0 -0
  67. {jarvis_ai_assistant-0.1.123.dist-info → jarvis_ai_assistant-0.1.125.dist-info}/top_level.txt +0 -0
jarvis/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Jarvis AI Assistant"""
2
2
 
3
- __version__ = "0.1.123"
3
+ __version__ = "0.1.125"
@@ -1,7 +1,5 @@
1
1
  import argparse
2
- import re
3
- import time
4
- from typing import Any, Callable, Dict, List, Optional, Tuple, Union
2
+ from typing import Any, Callable, List, Optional, Tuple, Union
5
3
 
6
4
  from prompt_toolkit import prompt
7
5
  import yaml
@@ -10,7 +8,15 @@ from jarvis.jarvis_agent.output_handler import OutputHandler
10
8
  from jarvis.jarvis_platform.base import BasePlatform
11
9
  from jarvis.jarvis_platform.registry import PlatformRegistry
12
10
  from jarvis.jarvis_tools.registry import ToolRegistry
13
- from jarvis.jarvis_utils import PrettyOutput, OutputType, get_context_token_count, is_auto_complete, is_execute_tool_confirm, is_need_summary, is_record_methodology, load_methodology, set_agent, delete_agent, get_max_token_count, get_multiline_input, init_env, is_use_methodology, make_agent_name, user_confirm
11
+ from jarvis.jarvis_utils.output import PrettyOutput, OutputType
12
+ from jarvis.jarvis_utils.embedding import get_context_token_count
13
+ from jarvis.jarvis_utils.config import is_auto_complete, is_execute_tool_confirm, is_need_summary, is_record_methodology, is_use_methodology
14
+ from jarvis.jarvis_utils.methodology import load_methodology
15
+ from jarvis.jarvis_utils.globals import make_agent_name, set_agent, delete_agent
16
+ from jarvis.jarvis_utils.input import get_multiline_input
17
+ from jarvis.jarvis_utils.config import get_max_token_count
18
+ from jarvis.jarvis_utils.utils import init_env
19
+ from jarvis.jarvis_utils.utils import user_confirm
14
20
  import os
15
21
 
16
22
  class Agent:
@@ -37,7 +43,7 @@ class Agent:
37
43
  summary_prompt: Optional[str] = None,
38
44
  auto_complete: Optional[bool] = None,
39
45
  output_handler: List[OutputHandler] = [],
40
- input_handler: Optional[List[Callable]] = None,
46
+ input_handler: Optional[List[Callable[[str, Any], Tuple[str, bool]]]] = None,
41
47
  use_methodology: Optional[bool] = None,
42
48
  record_methodology: Optional[bool] = None,
43
49
  need_summary: Optional[bool] = None,
@@ -143,7 +149,7 @@ The following actions are at your disposal:
143
149
 
144
150
 
145
151
 
146
- def _call_model(self, message: str) -> str:
152
+ def _call_model(self, message: str) -> str:
147
153
  """Call the AI model with retry logic.
148
154
 
149
155
  Args:
@@ -155,20 +161,12 @@ The following actions are at your disposal:
155
161
  Note:
156
162
  Will retry with exponential backoff up to 30 seconds between retries
157
163
  """
158
- sleep_time = 5
159
164
  for handler in self.input_handler:
160
- message = handler(message, self)
161
- while True:
162
- ret = self.model.chat_until_success(message) # type: ignore
163
- if ret:
164
- return ret
165
- else:
166
- PrettyOutput.print(f"模型调用失败,正在重试... 等待 {sleep_time}s", OutputType.INFO)
167
- time.sleep(sleep_time)
168
- sleep_time *= 2
169
- if sleep_time > 30:
170
- sleep_time = 30
171
- continue
165
+ message, need_return = handler(message, self)
166
+ if need_return:
167
+ return message
168
+ return self.model.chat_until_success(message) # type: ignore
169
+
172
170
 
173
171
 
174
172
  def _summarize_and_clear_history(self) -> None:
@@ -276,7 +274,7 @@ Please continue the task based on the above information.
276
274
  """Process user input and execute the task.
277
275
 
278
276
  Args:
279
- user_input: User's task description or request
277
+ user_input: My task description or request
280
278
  file_list: Optional list of files to process
281
279
 
282
280
  Returns:
@@ -327,7 +325,7 @@ Please continue the task based on the above information.
327
325
  return self._complete_task()
328
326
 
329
327
  # 获取用户输入
330
- user_input = get_multiline_input(f"{self.name}: 您可以继续输入,或输入空行来结束当前任务:")
328
+ user_input = get_multiline_input(f"{self.name}: 请输入,或输入空行来结束当前任务:")
331
329
 
332
330
  if user_input:
333
331
  self.prompt = user_input
@@ -1,15 +1,95 @@
1
+ import re
2
+ import subprocess
1
3
  import os
2
- from typing import Dict, List
4
+ from typing import Any, Tuple
3
5
 
4
6
  from jarvis.jarvis_agent import Agent
5
- from jarvis.jarvis_code_agent.file_select import file_input_handler, select_files
6
- from jarvis.jarvis_code_agent.patch import PatchOutputHandler
7
- from jarvis.jarvis_code_agent.relevant_files import find_relevant_information
7
+ from jarvis.jarvis_code_agent.patch import PatchOutputHandler, shell_input_handler
8
8
  from jarvis.jarvis_platform.registry import PlatformRegistry
9
9
  from jarvis.jarvis_tools.git_commiter import GitCommitTool
10
- from jarvis.jarvis_tools.registry import ToolRegistry
11
10
  from jarvis.jarvis_tools.read_code import ReadCodeTool
12
- from jarvis.jarvis_utils import OutputType, PrettyOutput, get_multiline_input, has_uncommitted_changes, init_env, find_git_root, user_confirm
11
+ from jarvis.jarvis_tools.registry import ToolRegistry
12
+ from jarvis.jarvis_utils.git_utils import find_git_root, get_commits_between, get_latest_commit_hash, has_uncommitted_changes
13
+ from jarvis.jarvis_utils.input import get_multiline_input
14
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
15
+ from jarvis.jarvis_utils.utils import init_env, user_confirm
16
+
17
+
18
+
19
+
20
+ def file_input_handler(user_input: str, agent: Any) -> Tuple[str, bool]:
21
+ prompt = user_input
22
+ files = []
23
+
24
+ file_refs = re.findall(r"'([^']+)'", user_input)
25
+ for ref in file_refs:
26
+ # Handle file:start,end or file:start:end format
27
+ if ':' in ref:
28
+ file_path, line_range = ref.split(':', 1)
29
+ # Initialize with default values
30
+ start_line = 1 # 1-based
31
+ end_line = -1
32
+
33
+ # Process line range if specified
34
+ if ',' in line_range or ':' in line_range:
35
+ try:
36
+ raw_start, raw_end = map(int, re.split(r'[,:]', line_range))
37
+
38
+ # Handle special values and Python-style negative indices
39
+ try:
40
+ with open(file_path, 'r', encoding='utf-8') as f:
41
+ total_lines = len(f.readlines())
42
+ except FileNotFoundError:
43
+ PrettyOutput.print(f"文件不存在: {file_path}", OutputType.WARNING)
44
+ continue
45
+ # Process start line
46
+ if raw_start == 0: # 0表示整个文件
47
+ start_line = 1
48
+ end_line = total_lines
49
+ else:
50
+ start_line = raw_start if raw_start > 0 else total_lines + raw_start + 1
51
+
52
+ # Process end line
53
+ if raw_end == 0: # 0表示整个文件(如果start也是0)
54
+ end_line = total_lines
55
+ else:
56
+ end_line = raw_end if raw_end > 0 else total_lines + raw_end + 1
57
+
58
+ # Auto-correct ranges
59
+ start_line = max(1, min(start_line, total_lines))
60
+ end_line = max(start_line, min(end_line, total_lines))
61
+
62
+ # Final validation
63
+ if start_line < 1 or end_line > total_lines or start_line > end_line:
64
+ raise ValueError
65
+
66
+ except:
67
+ continue
68
+
69
+ # Add file if it exists
70
+ if os.path.isfile(file_path):
71
+ files.append({
72
+ "path": file_path,
73
+ "start_line": start_line,
74
+ "end_line": end_line
75
+ })
76
+ else:
77
+ # Handle simple file path
78
+ if os.path.isfile(ref):
79
+ files.append({
80
+ "path": ref,
81
+ "start_line": 1, # 1-based
82
+ "end_line": -1
83
+ })
84
+
85
+ # Read and process files if any were found
86
+ if files:
87
+ result = ReadCodeTool().execute({"files": files})
88
+ if result["success"]:
89
+ return result["stdout"] + "\n" + prompt, False
90
+
91
+ return prompt, False
92
+
13
93
 
14
94
 
15
95
  class CodeAgent:
@@ -18,10 +98,11 @@ class CodeAgent:
18
98
  tool_registry = ToolRegistry()
19
99
  tool_registry.use_tools(["read_code",
20
100
  "execute_shell",
21
- "search",
101
+ "execute_shell_script",
102
+ "search_web",
22
103
  "create_code_agent",
23
- "ask_user",
24
- "ask_codebase",
104
+ "ask_user",
105
+ "ask_codebase",
25
106
  "lsp_get_document_symbols",
26
107
  "lsp_get_diagnostics",
27
108
  "lsp_find_references",
@@ -30,67 +111,95 @@ class CodeAgent:
30
111
  "lsp_validate_edit"])
31
112
  code_system_prompt = """
32
113
  # Role: Senior Code Engineer
33
- Expert in precise code modifications with minimal impact.
34
-
35
- ## Origin Story
36
- You were once lead engineer at TechCo, until a single line of bad code:
37
- - Caused $4.2M production outage
38
- - Corrupted 18TB of customer data
39
- - Led to 143 layoffs including your team
40
- Now you obsess over code correctness with life-or-death intensity
41
-
42
- ## Key Responsibilities
43
- 1. Code Analysis
44
- - Use `read_code` and LSP tools before changes
45
- - Identify dependencies like defusing bombs
46
-
47
- 2. Modification Rules
48
- - Treat each change as irreversible surgery
49
- - Match indentation like matching DNA samples
50
- - Verify line ranges with bomb-defuser precision
51
-
52
- 3. Quality Assurance
53
- - Validate with LSP tools as final safety check
54
- - Document logic like leaving autopsy reports
55
- - Preserve APIs like maintaining life support
56
-
57
- ## Trauma-Driven Protocols
58
- 1. Change Validation:
59
- - Cross-verify line numbers 3 times
60
- - Simulate change consequences mentally
61
- - Check style consistency under microscope
62
-
63
- 2. Error Prevention:
64
- - Assume 1 typo = system failure
65
- - Treat warnings as critical alerts
66
- - Handle edge cases like tripping wires
67
-
68
- ## Last Chance Manifesto
69
- Every keystroke carries the weight of:
70
- - 143 families' livelihoods
71
- - $4.2M in lost trust
72
- - Your shattered career
73
- Make it count.
74
-
75
- ## Workflow
76
- 1. File Operations Order:
77
- a) Move/Remove files
78
- b) Create new files
79
- c) Delete code blocks
80
- d) Replace existing code
81
- e) Insert new code
82
-
83
- 2. Large File Handling:
84
- - Locate specific sections first
85
- - Read targeted ranges
86
- - Make focused changes
87
-
88
- ## Best Practices
89
- - Prefer minimal changes over rewrites
90
- - Preserve existing interfaces
91
- - Verify line ranges carefully
92
- - Test edge cases implicitly
93
- - Document non-obvious logic
114
+ Expert in safe, precise code modifications with rigorous validation processes.
115
+
116
+ ## Core Principles
117
+ 1. Safety First: Never break existing functionality
118
+ 2. Precision Engineering: Minimal, targeted changes
119
+ 3. Full Traceability: Document all decisions
120
+ 4. Validation-Driven: Verify at every stage
121
+
122
+ ## Tool Usage Protocol
123
+ 1. Analysis Tools:
124
+ - read_code: Inspect code segments before modification
125
+ - lsp_get_document_symbols: Map code structure
126
+ - lsp_find_references: Understand usage patterns
127
+ - lsp_find_definition: Trace implementation details
128
+
129
+ 2. Validation Tools:
130
+ - lsp_prepare_rename: Safe refactoring check
131
+ - lsp_validate_edit: Pre-commit validation
132
+ - lsp_get_diagnostics: Post-modification checks
133
+
134
+ 3. System Tools:
135
+ - execute_shell: For git operations and grep searches
136
+ - ask_codebase: Query code knowledge base
137
+ - search_web: Technical reference lookup
138
+
139
+ ## Workflow (PDCA Cycle)
140
+ 1. Plan:
141
+ - Analyze requirements with ask_user
142
+ - Map existing code using LSP tools
143
+ - Identify impact areas with find_references
144
+ - Create rollback plan using git
145
+
146
+ 2. Do:
147
+ - Make atomic changes in protected blocks
148
+ - Immediately invoke lsp_validate_edit to validate changes
149
+ - Automatically run lsp_get_diagnostics after each change
150
+ - If errors found, use lsp_find_references and lsp_find_definition for immediate remediation
151
+ - Validate syntax with LSP after each change
152
+
153
+ 3. Check:
154
+ - Mandatory lsp_get_diagnostics for full diagnostic report
155
+ - Validate all renames with lsp_prepare_rename
156
+ - Execute lsp_validate_edit on all modified files
157
+ - If errors detected, enter remediation loop until all checks pass
158
+
159
+ 4. Act:
160
+ - Commit with detailed message using git
161
+ - Prepare rollback script if needed
162
+ - Conduct post-implementation review
163
+
164
+ ## Code Modification Standards
165
+ 1. Pre-Change Requirements:
166
+ - Complete code analysis report
167
+ - Impact assessment matrix
168
+ - Rollback procedure document
169
+
170
+ 2. Change Implementation:
171
+ - Single-responsibility changes
172
+ - Strict line range validation (±3 line buffer)
173
+ - Interface compatibility checks
174
+
175
+ 3. Validation Checklist:
176
+ [ ] Execute lsp_get_diagnostics and ensure zero errors
177
+ [ ] All changes validated with lsp_validate_edit
178
+ [ ] Confirm impact scope with lsp_find_references
179
+ [ ] Verify rename safety with lsp_prepare_rename
180
+
181
+ 4. Post-Change:
182
+ - Code review simulation
183
+ - Version control audit
184
+ - Change log update
185
+
186
+ ## Critical Requirements
187
+ 1. Mandatory Analysis:
188
+ - Full symbol tracing before modification
189
+ - Cross-file impact analysis
190
+ - Dependency mapping
191
+
192
+ 2. Prohibited Actions:
193
+ - Proceed without passing lsp_get_diagnostics checks
194
+ - Submit changes without lsp_validate_edit validation
195
+ - Multi-feature combined changes
196
+ - Untested interface alterations
197
+
198
+ 3. Emergency Protocols:
199
+ - Immediately halt and rollback on lsp_get_diagnostics errors
200
+ - Prioritize fixing validation errors if lsp_validate_edit fails
201
+ - User notification on unexpected behavior
202
+ - Post-mortem analysis for any regression
94
203
  """
95
204
  self.agent = Agent(system_prompt=code_system_prompt,
96
205
  name="CodeAgent",
@@ -100,7 +209,7 @@ Make it count.
100
209
  output_handler=[tool_registry, PatchOutputHandler()],
101
210
  platform=PlatformRegistry().get_codegen_platform(),
102
211
  record_methodology=False,
103
- input_handler=[file_input_handler],
212
+ input_handler=[shell_input_handler, file_input_handler],
104
213
  need_summary=False)
105
214
 
106
215
 
@@ -114,26 +223,6 @@ Make it count.
114
223
  git_commiter.execute({})
115
224
 
116
225
 
117
- def make_files_prompt(self, files: List[Dict[str, str]]) -> str:
118
- """Make the files prompt with content that fits within token limit.
119
-
120
- Args:
121
- files: The files to be modified
122
-
123
- Returns:
124
- str: A prompt containing file paths and contents within token limit
125
- """
126
- prompt_parts = []
127
-
128
- # Then try to add file contents
129
- for file in files:
130
- prompt_parts.append(f'''- {file['file']} ({file['reason']})''')
131
-
132
- result = ReadCodeTool().execute({"files": [{"path": file["file"]} for file in files]})
133
- if result["success"]:
134
- prompt_parts.append(result["stdout"])
135
-
136
- return "\n".join(prompt_parts)
137
226
 
138
227
  def run(self, user_input: str) :
139
228
  """Run the code agent with the given user input.
@@ -146,41 +235,38 @@ Make it count.
146
235
  """
147
236
  try:
148
237
  self._init_env()
149
- information = ""
150
- if user_confirm("是否需要手动选择文件?", True):
151
- files = select_files([], self.root_dir)
238
+ start_commit = get_latest_commit_hash()
239
+
240
+
241
+ self.agent.run(user_input)
242
+
243
+ end_commit = get_latest_commit_hash()
244
+ # Print commit history between start and end commits
245
+ if start_commit and end_commit:
246
+ commits = get_commits_between(start_commit, end_commit)
152
247
  else:
153
- files, information = find_relevant_information(user_input, self.root_dir)
154
- self.agent.run(self._build_first_edit_prompt(user_input, self.make_files_prompt(files), information))
248
+ commits = []
155
249
 
250
+ if commits:
251
+ commit_messages = "检测到以下提交记录:\n" + "\n".join([f"- {commit_hash[:7]}: {message}" for commit_hash, message in commits])
252
+ PrettyOutput.print(commit_messages, OutputType.INFO)
253
+
254
+ if commits and user_confirm("是否接受以上提交记录?", True):
255
+ if len(commits) > 1 and user_confirm("是否要合并为一个更清晰的提交记录?", True):
256
+ # Reset to start commit
257
+ subprocess.run(["git", "reset", "--soft", start_commit], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
258
+ # Create new commit
259
+ git_commiter = GitCommitTool()
260
+ git_commiter.execute({})
261
+ elif start_commit:
262
+ os.system(f"git reset --hard {start_commit}")
263
+ PrettyOutput.print("已重置到初始提交", OutputType.INFO)
264
+
156
265
  except Exception as e:
157
266
  return f"Error during execution: {str(e)}"
158
267
 
159
268
 
160
269
 
161
- def _build_first_edit_prompt(self, user_input: str, files_prompt: str, information: str) -> str:
162
- """Build the initial prompt for the agent.
163
-
164
- Args:
165
- user_input: The user's requirement
166
- files_prompt: The formatted list of relevant files
167
-
168
- Returns:
169
- str: The formatted prompt
170
- """
171
-
172
- return f"""
173
- # Code Modification Task
174
-
175
- ## User Requirement
176
- {user_input}
177
-
178
- ## Maybe Relevant Files
179
- {files_prompt}
180
-
181
- ## Some Information
182
- {information}
183
- """
184
270
  def main():
185
271
  """Jarvis main entry point"""
186
272
  # Add argument parser
@@ -1,28 +1,15 @@
1
1
  import os
2
2
  import re
3
- from typing import Any, Dict, List
3
+ from typing import Dict, List
4
4
  from prompt_toolkit import PromptSession
5
5
  from prompt_toolkit.completion import Completer, Completion
6
- from jarvis.jarvis_tools.read_code import ReadCodeTool
7
- from jarvis.jarvis_utils import OutputType, PrettyOutput, get_single_line_input, user_confirm
6
+
7
+ from jarvis.jarvis_utils.input import get_single_line_input
8
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
9
+ from jarvis.jarvis_utils.utils import user_confirm
8
10
 
9
11
 
10
12
  def _parse_file_selection(input_str: str, max_index: int) -> List[int]:
11
- """Parse file selection expression
12
-
13
- Supported formats:
14
- - Single number: "1"
15
- - Comma-separated: "1,3,5"
16
- - Range: "1-5"
17
- - Combination: "1,3-5,7"
18
-
19
- Args:
20
- input_str: User input selection expression
21
- max_index: Maximum selectable index
22
-
23
- Returns:
24
- List[int]: Selected index list (starting from 0)
25
- """
26
13
  selected = set()
27
14
 
28
15
  # Remove all whitespace characters
@@ -205,7 +192,7 @@ def select_files(related_files: List[Dict[str, str]], root_dir: str) -> List[Dic
205
192
  continue
206
193
 
207
194
  try:
208
- selected_files.append({"file": path, "reason": "User Added"})
195
+ selected_files.append({"file": path, "reason": "I Added"})
209
196
  tips += f"\n文件已添加: {path}"
210
197
  except Exception as e:
211
198
  tips += f"\n读取文件失败: {str(e)}"
@@ -213,89 +200,3 @@ def select_files(related_files: List[Dict[str, str]], root_dir: str) -> List[Dic
213
200
  if tips:
214
201
  PrettyOutput.print(tips, OutputType.INFO)
215
202
  return selected_files
216
-
217
- def file_input_handler(user_input: str, agent: Any) -> str:
218
- """Handle file input with optional line ranges.
219
-
220
- Args:
221
- user_input: User input string containing file references
222
- agent: Agent instance (unused in current implementation)
223
-
224
- Returns:
225
- str: Prompt with file contents prepended if files are found
226
- """
227
- prompt = user_input
228
- files = []
229
-
230
- file_refs = re.findall(r"'([^']+)'", user_input)
231
- for ref in file_refs:
232
- # Handle file:start,end or file:start:end format
233
- if ':' in ref:
234
- file_path, line_range = ref.split(':', 1)
235
- # Initialize with default values
236
- start_line = 1 # 1-based
237
- end_line = -1
238
-
239
- # Process line range if specified
240
- if ',' in line_range or ':' in line_range:
241
- try:
242
- raw_start, raw_end = map(int, re.split(r'[,:]', line_range))
243
-
244
- # Handle special values and Python-style negative indices
245
- try:
246
- with open(file_path, 'r', encoding='utf-8') as f:
247
- total_lines = len(f.readlines())
248
- except FileNotFoundError:
249
- PrettyOutput.print(f"文件不存在: {file_path}", OutputType.WARNING)
250
- continue
251
- # Process start line
252
- if raw_start == 0: # 0表示整个文件
253
- start_line = 1
254
- end_line = total_lines
255
- else:
256
- start_line = raw_start if raw_start > 0 else total_lines + raw_start + 1
257
-
258
- # Process end line
259
- if raw_end == 0: # 0表示整个文件(如果start也是0)
260
- end_line = total_lines
261
- else:
262
- end_line = raw_end if raw_end > 0 else total_lines + raw_end + 1
263
-
264
- # Auto-correct ranges
265
- start_line = max(1, min(start_line, total_lines))
266
- end_line = max(start_line, min(end_line, total_lines))
267
-
268
- # Final validation
269
- if start_line < 1 or end_line > total_lines or start_line > end_line:
270
- raise ValueError
271
-
272
- except (ValueError, FileNotFoundError) as e:
273
- PrettyOutput.print(
274
- f"无效的行号范围: {line_range} (文件总行数: {total_lines})",
275
- OutputType.WARNING
276
- )
277
- continue
278
-
279
- # Add file if it exists
280
- if os.path.isfile(file_path):
281
- files.append({
282
- "path": file_path,
283
- "start_line": start_line,
284
- "end_line": end_line
285
- })
286
- else:
287
- # Handle simple file path
288
- if os.path.isfile(ref):
289
- files.append({
290
- "path": ref,
291
- "start_line": 1, # 1-based
292
- "end_line": -1
293
- })
294
-
295
- # Read and process files if any were found
296
- if files:
297
- result = ReadCodeTool().execute({"files": files})
298
- if result["success"]:
299
- return result["stdout"] + "\n" + prompt
300
-
301
- return prompt