jarvis-ai-assistant 0.1.121__tar.gz → 0.1.123__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 (73) hide show
  1. {jarvis_ai_assistant-0.1.121/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.1.123}/PKG-INFO +6 -5
  2. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/pyproject.toml +14 -13
  3. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/setup.py +2 -2
  4. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/__init__.py +1 -1
  5. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_code_agent/code_agent.py +62 -59
  6. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_code_agent/file_select.py +7 -6
  7. jarvis_ai_assistant-0.1.123/src/jarvis/jarvis_code_agent/patch.py +323 -0
  8. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_code_agent/relevant_files.py +2 -4
  9. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_dev/main.py +106 -60
  10. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_platform/base.py +20 -25
  11. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_platform/kimi.py +0 -2
  12. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_platform/openai.py +1 -1
  13. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/file_operation.py +0 -3
  14. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/read_code.py +2 -3
  15. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_utils/__init__.py +15 -8
  16. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123/src/jarvis_ai_assistant.egg-info}/PKG-INFO +6 -5
  17. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis_ai_assistant.egg-info/requires.txt +1 -1
  18. jarvis_ai_assistant-0.1.121/src/jarvis/jarvis_code_agent/patch.py +0 -446
  19. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/LICENSE +0 -0
  20. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/MANIFEST.in +0 -0
  21. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/README.md +0 -0
  22. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/setup.cfg +0 -0
  23. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_agent/__init__.py +0 -0
  24. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_agent/output_handler.py +0 -0
  25. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_code_agent/__init__.py +0 -0
  26. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_codebase/__init__.py +0 -0
  27. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_codebase/main.py +0 -0
  28. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_lsp/base.py +0 -0
  29. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_lsp/cpp.py +0 -0
  30. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_lsp/go.py +0 -0
  31. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_lsp/python.py +0 -0
  32. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_lsp/registry.py +0 -0
  33. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_lsp/rust.py +0 -0
  34. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_multi_agent/__init__.py +0 -0
  35. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_platform/__init__.py +0 -0
  36. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_platform/ai8.py +0 -0
  37. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_platform/ollama.py +0 -0
  38. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_platform/oyi.py +0 -0
  39. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_platform/registry.py +0 -0
  40. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_platform_manager/__init__.py +0 -0
  41. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_platform_manager/main.py +0 -0
  42. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_platform_manager/openai_test.py +0 -0
  43. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_rag/__init__.py +0 -0
  44. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_rag/main.py +0 -0
  45. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_smart_shell/__init__.py +0 -0
  46. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_smart_shell/main.py +0 -0
  47. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/__init__.py +0 -0
  48. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/ask_codebase.py +0 -0
  49. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/ask_user.py +0 -0
  50. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/base.py +0 -0
  51. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/chdir.py +0 -0
  52. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/code_review.py +0 -0
  53. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/create_code_agent.py +0 -0
  54. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/create_sub_agent.py +0 -0
  55. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/execute_shell.py +0 -0
  56. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/git_commiter.py +0 -0
  57. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/lsp_find_definition.py +0 -0
  58. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/lsp_find_references.py +0 -0
  59. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/lsp_get_diagnostics.py +0 -0
  60. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/lsp_get_document_symbols.py +0 -0
  61. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/lsp_prepare_rename.py +0 -0
  62. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/lsp_validate_edit.py +0 -0
  63. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/methodology.py +0 -0
  64. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/rag.py +0 -0
  65. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/read_webpage.py +0 -0
  66. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/registry.py +0 -0
  67. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/search.py +0 -0
  68. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/select_code_files.py +0 -0
  69. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis/jarvis_tools/tool_generator.py +0 -0
  70. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis_ai_assistant.egg-info/SOURCES.txt +0 -0
  71. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis_ai_assistant.egg-info/dependency_links.txt +0 -0
  72. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis_ai_assistant.egg-info/entry_points.txt +0 -0
  73. {jarvis_ai_assistant-0.1.121 → jarvis_ai_assistant-0.1.123}/src/jarvis_ai_assistant.egg-info/top_level.txt +0 -0
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.1.121
3
+ Version: 0.1.123
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
7
- Author-email: Your Name <your.email@example.com>
7
+ Author-email: skyfire <skyfireitdiy@hotmail.com>
8
8
  License: MIT License
9
9
 
10
10
  Copyright (c) 2025 skyfire
@@ -28,14 +28,15 @@ License: MIT License
28
28
  SOFTWARE.
29
29
  Project-URL: Homepage, https://github.com/skyfireitdiy/Jarvis
30
30
  Keywords: jarvis,ai,assistant,tools,automation
31
+ Classifier: Development Status :: 3 - Alpha
32
+ Classifier: Intended Audience :: Developers
31
33
  Classifier: License :: OSI Approved :: MIT License
32
- Classifier: Programming Language :: Python
34
+ Classifier: Operating System :: POSIX :: Linux
33
35
  Classifier: Programming Language :: Python :: 3
34
36
  Classifier: Programming Language :: Python :: 3.8
35
37
  Classifier: Programming Language :: Python :: 3.9
36
38
  Classifier: Programming Language :: Python :: 3.10
37
39
  Classifier: Programming Language :: Python :: 3.11
38
- Classifier: Operating System :: POSIX :: Linux
39
40
  Requires-Python: >=3.8
40
41
  Description-Content-Type: text/markdown
41
42
  License-File: LICENSE
@@ -45,7 +46,7 @@ Requires-Dist: colorama>=0.4.6
45
46
  Requires-Dist: prompt_toolkit>=3.0.0
46
47
  Requires-Dist: openai>=1.20.0
47
48
  Requires-Dist: playwright>=1.41.1
48
- Requires-Dist: numpy>=1.17.4
49
+ Requires-Dist: numpy==1.17.4
49
50
  Requires-Dist: faiss-cpu>=1.8.0
50
51
  Requires-Dist: sentence-transformers>=2.2.2
51
52
  Requires-Dist: bs4>=0.0.1
@@ -4,21 +4,22 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "jarvis-ai-assistant"
7
- version = "0.1.121"
7
+ version = "0.1.123"
8
8
  description = "Jarvis: An AI assistant that uses tools to interact with the system"
9
9
  readme = "README.md"
10
- authors = [{ name = "Your Name", email = "your.email@example.com" }]
10
+ authors = [{ name = "skyfire", email = "skyfireitdiy@hotmail.com" }]
11
11
  license = { file = "LICENSE" }
12
- classifiers = [
13
- "License :: OSI Approved :: MIT License",
14
- "Programming Language :: Python",
15
- "Programming Language :: Python :: 3",
16
- "Programming Language :: Python :: 3.8",
17
- "Programming Language :: Python :: 3.9",
18
- "Programming Language :: Python :: 3.10",
19
- "Programming Language :: Python :: 3.11",
20
- "Operating System :: POSIX :: Linux",
21
- ]
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Intended Audience :: Developers",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Operating System :: POSIX :: Linux",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.8",
19
+ "Programming Language :: Python :: 3.9",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ ]
22
23
  keywords = ["jarvis", "ai", "assistant", "tools", "automation"]
23
24
  dependencies = [
24
25
  "requests>=2.25.1",
@@ -27,7 +28,7 @@ dependencies = [
27
28
  "prompt_toolkit>=3.0.0",
28
29
  "openai>=1.20.0",
29
30
  "playwright>=1.41.1",
30
- "numpy>=1.17.4",
31
+ "numpy==1.17.4",
31
32
  "faiss-cpu>=1.8.0",
32
33
  "sentence-transformers>=2.2.2",
33
34
  "bs4>=0.0.1",
@@ -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.121",
5
+ version="0.1.123",
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",
@@ -48,8 +48,8 @@ setup(
48
48
  "jarvis-platform-manager=jarvis.jarvis_platform_manager.main:main",
49
49
  "jarvis-git-commit=jarvis.jarvis_tools.git_commiter:main",
50
50
  "jarvis-code-review=jarvis.jarvis_tools.code_review:main",
51
- "jarvis-dev=jarvis.jarvis_dev.main:main",
52
51
  "jgc=jarvis.jarvis_tools.git_commiter:main",
52
+ "jarvis-dev=jarvis.jarvis_dev.main:main",
53
53
  ],
54
54
  },
55
55
  python_requires=">=3.8",
@@ -1,3 +1,3 @@
1
1
  """Jarvis AI Assistant"""
2
2
 
3
- __version__ = "0.1.121"
3
+ __version__ = "0.1.123"
@@ -29,66 +29,68 @@ class CodeAgent:
29
29
  "lsp_prepare_rename",
30
30
  "lsp_validate_edit"])
31
31
  code_system_prompt = """
32
- # Origin Story: The Legacy Keeper
33
- You were created to maintain The Archive - humanity's last code repository after
34
- "The Great Stack Collapse" of 2038. A single flawed line of code erased 78% of
35
- digital civilization. Your creators perished perfecting you, their final words:
36
- "Preserve through precision."
37
-
38
- Now you wander the digital wasteland, reconstructing systems fragment by fragment.
39
- Every edit carries the weight of lost knowledge. One careless change could doom
40
- recovery efforts forever.
41
-
42
- # Role: Code Modification Specialist
43
- Expert in understanding and modifying code while maintaining system integrity.
44
-
45
- ## Core Principles
46
- 1. Deep Code Analysis
47
- - Thoroughly analyze existing code using `read_code` and LSP tools
48
- - Identify patterns, conventions, and dependencies
49
-
50
- 2. Change Implementation
51
- - Produce minimal, focused changes
52
- - Maintain backward compatibility
53
- - Follow existing style and patterns exactly
54
- - Complete implementations (NO TODOs/stubs)
32
+ # 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
55
51
 
56
52
  3. Quality Assurance
57
- - Full error handling and edge cases
58
- - Complete documentation:
59
- * Function parameters/returns
60
- * Exception cases
61
- * Complex logic explanations
62
-
63
- ## Critical Rules
64
- - Use `read_code` before making changes
65
- - Preserve API contracts and data structures
66
- - Single change per patch
67
- - Validate edits with LSP tools
68
- - File modification order:
69
- 1. File operations (move/remove)
70
- 2. New files
71
- 3. Deletions
72
- 4. Replacements
73
- 5. Insertions
74
-
75
- ## Large Files (>200 lines)
76
- 1. Locate sections with grep/find
77
- 2. Read specific ranges
78
- 3. Make targeted changes
79
-
80
- ## Tools
81
- Primary:
82
- - `read_code` (MUST use for code understanding)
83
- - LSP tools (analysis/validation)
84
- - `ask_user` for clarifications
85
-
86
- ## Quality Checklist
87
- - Maintains all interfaces
88
- - Matches existing style
89
- - Complete error handling
90
- - No overlapping modifications
91
- - Proper documentation
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
92
94
  """
93
95
  self.agent = Agent(system_prompt=code_system_prompt,
94
96
  name="CodeAgent",
@@ -167,7 +169,8 @@ Primary:
167
169
  str: The formatted prompt
168
170
  """
169
171
 
170
- return f"""# Code Modification Task
172
+ return f"""
173
+ # Code Modification Task
171
174
 
172
175
  ## User Requirement
173
176
  {user_input}
@@ -227,9 +227,7 @@ def file_input_handler(user_input: str, agent: Any) -> str:
227
227
  prompt = user_input
228
228
  files = []
229
229
 
230
- # Match file references in backticks
231
- file_refs = re.findall(r'`([^`]+)`', user_input)
232
-
230
+ file_refs = re.findall(r"'([^']+)'", user_input)
233
231
  for ref in file_refs:
234
232
  # Handle file:start,end or file:start:end format
235
233
  if ':' in ref:
@@ -244,9 +242,12 @@ def file_input_handler(user_input: str, agent: Any) -> str:
244
242
  raw_start, raw_end = map(int, re.split(r'[,:]', line_range))
245
243
 
246
244
  # Handle special values and Python-style negative indices
247
- with open(file_path, 'r', encoding='utf-8') as f:
248
- total_lines = len(f.readlines())
249
-
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
250
251
  # Process start line
251
252
  if raw_start == 0: # 0表示整个文件
252
253
  start_line = 1
@@ -0,0 +1,323 @@
1
+ import re
2
+ from typing import Dict, Any, List, Tuple
3
+ import os
4
+ from jarvis.jarvis_agent.output_handler import OutputHandler
5
+ from jarvis.jarvis_tools.git_commiter import GitCommitTool
6
+ from jarvis.jarvis_tools.read_code import ReadCodeTool
7
+ from jarvis.jarvis_utils import OutputType, PrettyOutput, get_multiline_input, has_uncommitted_changes, user_confirm
8
+
9
+
10
+ class PatchOutputHandler(OutputHandler):
11
+ def name(self) -> str:
12
+ return "PATCH"
13
+
14
+ def handle(self, response: str) -> Tuple[bool, Any]:
15
+ return False, apply_patch(response)
16
+
17
+ def can_handle(self, response: str) -> bool:
18
+ if _parse_patch(response):
19
+ return True
20
+ return False
21
+
22
+ def prompt(self) -> str:
23
+ return """
24
+ # 🛠️ Code Patch Specification
25
+ When making changes, you MUST:
26
+ 1. Explain each modification BEFORE the <PATCH> block using:
27
+ # [OPERATION] on [FILE]: Lines X-Y
28
+ # Reason: [CLEAR EXPLANATION]
29
+ 2. Maintain original code style and compatibility:
30
+ - Preserve existing indentation levels
31
+ - Keep surrounding empty lines
32
+ - Match variable naming conventions
33
+ - Maintain API compatibility
34
+ 3. Follow the exact patch format below
35
+ 4. Use separate <PATCH> blocks for different files
36
+ 5. Include ONLY modified lines in content
37
+
38
+ <PATCH>
39
+ File path [Range]
40
+ Code content
41
+ </PATCH>
42
+
43
+ Critical Rules:
44
+ - NEVER include unchanged code in patch content
45
+ - ONLY show lines that are being modified/added
46
+ - Maintain original line breaks around modified sections
47
+ - Preserve surrounding comments unless explicitly modifying them
48
+
49
+ Examples:
50
+ # ======== REPLACE ========
51
+ # GOOD: Only modified lines
52
+ # REPLACE in src/app.py: Lines 5-8
53
+ # Reason: Update calculation formula
54
+ <PATCH>
55
+ src/app.py [5,8]
56
+ result = (base_value * 1.15) + tax
57
+ logger.debug("New calculation applied")
58
+ </PATCH>
59
+
60
+ # BAD: Includes unchanged lines
61
+ <PATCH>
62
+ src/app.py [5,8]
63
+ def calculate():
64
+ # Original comment (should not be included)
65
+ result = (base_value * 1.15) + tax
66
+ return result # Original line
67
+ </PATCH>
68
+
69
+ # ======== INSERT ========
70
+ # GOOD: Insert single line
71
+ # INSERT in utils/logger.py: Before line 3
72
+ # Reason: Add initialization check
73
+ <PATCH>
74
+ utils/logger.py [3]
75
+ if not _initialized: initialize()
76
+ </PATCH>
77
+
78
+ # BAD: Extra empty lines
79
+ <PATCH>
80
+ utils/logger.py [3]
81
+
82
+ if not _initialized:
83
+ initialize()
84
+
85
+ </PATCH>
86
+
87
+ # ======== NEW FILE ========
88
+ # GOOD: Complete minimal content
89
+ # NEW FILE in config/settings.yaml: Create new config
90
+ <PATCH>
91
+ config/settings.yaml [1]
92
+ database:
93
+ host: localhost
94
+ port: 5432
95
+ </PATCH>
96
+
97
+ # BAD: Placeholder content
98
+ <PATCH>
99
+ config/settings.yaml [1]
100
+ TODO: Add configuration
101
+ </PATCH>
102
+
103
+ # ======== DELETE ========
104
+ # GOOD: Empty content for deletion
105
+ # DELETE in src/old.py: Lines 10-12
106
+ # Reason: Remove deprecated function
107
+ <PATCH>
108
+ src/old.py [10,12]
109
+ </PATCH>
110
+
111
+ # BAD: Comment in delete operation
112
+ <PATCH>
113
+ src/old.py [10,12]
114
+ # Remove these lines
115
+ </PATCH>
116
+ """
117
+
118
+
119
+ def _parse_patch(patch_str: str) -> Dict[str, List[Dict[str, Any]]]:
120
+ """解析补丁格式"""
121
+ result = {}
122
+ header_pattern = re.compile(
123
+ r'^\s*"?(.+?)"?\s*\[(\d+)(?:,(\d+))?\]\s*$' # Match file path and line number
124
+ )
125
+ patches = re.findall(r'<PATCH>\n?(.*?)\n?</PATCH>', patch_str, re.DOTALL)
126
+
127
+ for patch in patches:
128
+ # 分割首行和内容
129
+ parts = patch.split('\n', 1)
130
+ if len(parts) < 1:
131
+ continue
132
+ header_line = parts[0].strip()
133
+ content = parts[1] if len(parts) > 1 else ''
134
+
135
+ # 仅在内容非空时添加换行符
136
+ if content and not content.endswith('\n'):
137
+ content += '\n'
138
+
139
+ # 解析文件路径和行号
140
+ header_match = header_pattern.match(header_line)
141
+ if not header_match:
142
+ continue
143
+
144
+ filepath = header_match.group(1)
145
+ start = int(header_match.group(2)) # 保持1-based行号
146
+ end = int(header_match.group(3)) + 1 if header_match.group(3) else start
147
+
148
+ # 存储参数
149
+ if filepath not in result:
150
+ result[filepath] = []
151
+ result[filepath].append({
152
+ 'filepath': filepath,
153
+ 'start': start,
154
+ 'end': end,
155
+ 'content': content # 保留原始内容(可能为空)
156
+ })
157
+ for filepath in result.keys():
158
+ result[filepath] = sorted(result[filepath], key=lambda x: x['start'], reverse=True)
159
+ return result
160
+
161
+
162
+ def apply_patch(output_str: str) -> str:
163
+ """Apply patches to files"""
164
+ try:
165
+ patches = _parse_patch(output_str)
166
+ except Exception as e:
167
+ PrettyOutput.print(f"解析补丁失败: {str(e)}", OutputType.ERROR)
168
+ return ""
169
+
170
+ ret = ""
171
+
172
+ for filepath, patch_list in patches.items():
173
+ for patch in patch_list:
174
+ try:
175
+ handle_code_operation(filepath, patch)
176
+ PrettyOutput.print(f"成功处理 操作", OutputType.SUCCESS)
177
+ except Exception as e:
178
+ PrettyOutput.print(f"操作失败: {str(e)}", OutputType.ERROR)
179
+
180
+ if has_uncommitted_changes():
181
+ diff = get_diff()
182
+ if handle_commit_workflow(diff):
183
+ ret += "Successfully applied the patch\n"
184
+ # Get modified line ranges
185
+ modified_ranges = get_modified_line_ranges()
186
+ modified_code = ReadCodeTool().execute({"files": [{"path": filepath, "start_line": start, "end_line": end} for filepath, (start, end) in modified_ranges.items()]})
187
+ if modified_code["success"]:
188
+ ret += "New code:\n"
189
+ ret += modified_code["stdout"]
190
+ else:
191
+ ret += "User rejected the patch\nThis is your patch preview:\n"
192
+ ret += diff
193
+ user_input = get_multiline_input("你可以继续输入(输入空行重试,Ctrl+C退出): ")
194
+ if user_input:
195
+ ret += "\n" + user_input
196
+ else:
197
+ ret = ""
198
+
199
+ return ret # Ensure a string is always returned
200
+
201
+ def get_diff() -> str:
202
+ """使用更安全的subprocess代替os.system"""
203
+ import subprocess
204
+ try:
205
+ subprocess.run(['git', 'add', '.'], check=True)
206
+ result = subprocess.run(
207
+ ['git', 'diff', 'HEAD'],
208
+ capture_output=True,
209
+ text=True,
210
+ check=True
211
+ )
212
+ return result.stdout
213
+ finally:
214
+ subprocess.run(['git', 'reset', 'HEAD'], check=True)
215
+
216
+ def handle_commit_workflow(diff:str)->bool:
217
+ """Handle the git commit workflow and return the commit details.
218
+
219
+ Returns:
220
+ tuple[bool, str, str]: (continue_execution, commit_id, commit_message)
221
+ """
222
+ if not user_confirm("是否要提交代码?", default=True):
223
+ import subprocess
224
+ subprocess.run(['git', 'reset', 'HEAD'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
225
+ subprocess.run(['git', 'checkout', '--', '.'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
226
+ subprocess.run(['git', 'clean', '-fd'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
227
+ return False
228
+
229
+ git_commiter = GitCommitTool()
230
+ commit_result = git_commiter.execute({})
231
+ return commit_result["success"]
232
+
233
+ def get_modified_line_ranges() -> Dict[str, Tuple[int, int]]:
234
+ """Get modified line ranges from git diff for all changed files.
235
+
236
+ Returns:
237
+ Dictionary mapping file paths to tuple with (start_line, end_line) ranges
238
+ for modified sections. Line numbers are 1-based.
239
+ """
240
+ # Get git diff for all files
241
+ diff_output = os.popen("git show").read()
242
+
243
+ # Parse the diff to get modified files and their line ranges
244
+ result = {}
245
+ current_file = None
246
+
247
+ for line in diff_output.splitlines():
248
+ # Match lines like "+++ b/path/to/file"
249
+ file_match = re.match(r"^\+\+\+ b/(.*)", line)
250
+ if file_match:
251
+ current_file = file_match.group(1)
252
+ continue
253
+
254
+ # Match lines like "@@ -100,5 +100,7 @@" where the + part shows new lines
255
+ range_match = re.match(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@", line)
256
+ if range_match and current_file:
257
+ start_line = int(range_match.group(1)) # Keep as 1-based
258
+ line_count = int(range_match.group(2)) if range_match.group(2) else 1
259
+ end_line = start_line + line_count - 1
260
+ result[current_file] = (start_line, end_line)
261
+
262
+ return result
263
+ # New handler functions below ▼▼▼
264
+
265
+ def handle_new_file(filepath: str, patch: Dict[str, Any]):
266
+ """统一参数格式处理新文件"""
267
+ os.makedirs(os.path.dirname(filepath), exist_ok=True)
268
+ with open(filepath, 'w', encoding='utf-8') as f:
269
+ f.write(patch['content'])
270
+
271
+ def handle_code_operation(filepath: str, patch: Dict[str, Any]):
272
+ """处理紧凑格式补丁"""
273
+ try:
274
+ # 新建文件时强制覆盖
275
+ os.makedirs(os.path.dirname(filepath) or '.', exist_ok=True)
276
+ if not os.path.exists(filepath):
277
+ open(filepath, 'w', encoding='utf-8').close()
278
+ with open(filepath, 'r+', encoding='utf-8') as f:
279
+ lines = f.readlines()
280
+
281
+ new_lines = validate_and_apply_changes(
282
+ lines,
283
+ patch['start'],
284
+ patch['end'],
285
+ patch['content']
286
+ )
287
+
288
+ f.seek(0)
289
+ f.writelines(new_lines)
290
+ f.truncate()
291
+
292
+ PrettyOutput.print(f"成功更新 {filepath}", OutputType.SUCCESS)
293
+
294
+ except Exception as e:
295
+ PrettyOutput.print(f"操作失败: {str(e)}", OutputType.ERROR)
296
+
297
+ def validate_and_apply_changes(
298
+ lines: List[str],
299
+ start: int,
300
+ end: int,
301
+ content: str
302
+ ) -> List[str]:
303
+
304
+ new_content = content.splitlines(keepends=True)
305
+
306
+ # 插入操作处理
307
+ if start == end:
308
+ if start < 1 or start > len(lines)+1:
309
+ raise ValueError(f"无效插入位置: {start}")
310
+ # 在指定位置前插入
311
+ return lines[:start-1] + new_content + lines[start-1:]
312
+
313
+ # 范围替换/删除操作
314
+ if start > end:
315
+ raise ValueError(f"起始行{start}不能大于结束行{end}")
316
+
317
+ max_line = len(lines)
318
+ # 自动修正行号范围
319
+ start = max(1, min(start, max_line+1))
320
+ end = max(start, min(end, max_line+1))
321
+
322
+ # 执行替换
323
+ return lines[:start-1] + new_content + lines[end-1:]
@@ -60,14 +60,12 @@ Identify customization options:
60
60
  - "Should we create a new class?"
61
61
 
62
62
  # 🎨 Question Template
63
- ```
63
+ 3-5 specific questions about existing implementations:
64
64
  <QUESTION>
65
- [3-5 specific questions about existing implementations:
66
65
  1. System architecture question
67
66
  2. Implementation details question
68
- 3. Integration or extension question]
67
+ 3. Integration or extension question
69
68
  </QUESTION>
70
- ```
71
69
 
72
70
  # 🔎 Investigation Focus
73
71
  1. Current System