jarvis-ai-assistant 0.1.103__py3-none-any.whl → 0.1.105__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.
- jarvis/__init__.py +1 -1
- jarvis/agent.py +124 -67
- jarvis/jarvis_code_agent/code_agent.py +133 -22
- jarvis/jarvis_code_agent/file_select.py +4 -6
- jarvis/jarvis_code_agent/patch.py +6 -7
- jarvis/jarvis_code_agent/relevant_files.py +163 -41
- jarvis/jarvis_codebase/main.py +43 -29
- jarvis/jarvis_lsp/base.py +143 -0
- jarvis/jarvis_lsp/cpp.py +134 -0
- jarvis/jarvis_lsp/go.py +140 -0
- jarvis/jarvis_lsp/python.py +135 -0
- jarvis/jarvis_lsp/registry.py +234 -0
- jarvis/jarvis_lsp/rust.py +142 -0
- jarvis/jarvis_platform/__init__.py +3 -0
- jarvis/{models → jarvis_platform}/ai8.py +1 -1
- jarvis/{models → jarvis_platform}/kimi.py +1 -1
- jarvis/{models → jarvis_platform}/ollama.py +1 -1
- jarvis/{models → jarvis_platform}/openai.py +1 -1
- jarvis/{models → jarvis_platform}/oyi.py +1 -1
- jarvis/{models → jarvis_platform}/registry.py +11 -11
- jarvis/{jarvis_platform → jarvis_platform_manager}/main.py +2 -2
- jarvis/jarvis_rag/main.py +8 -8
- jarvis/jarvis_smart_shell/main.py +3 -3
- jarvis/jarvis_tools/__init__.py +0 -0
- jarvis/{tools → jarvis_tools}/ask_codebase.py +1 -4
- jarvis/{tools → jarvis_tools}/ask_user.py +1 -1
- jarvis/{tools → jarvis_tools}/chdir.py +2 -37
- jarvis/jarvis_tools/code_review.py +236 -0
- jarvis/jarvis_tools/create_code_agent.py +115 -0
- jarvis/{tools → jarvis_tools}/create_sub_agent.py +1 -1
- jarvis/jarvis_tools/deep_thinking.py +160 -0
- jarvis/jarvis_tools/deep_thinking_agent.py +146 -0
- jarvis/{tools → jarvis_tools}/git_commiter.py +3 -3
- jarvis/jarvis_tools/lsp_find_definition.py +134 -0
- jarvis/jarvis_tools/lsp_find_references.py +111 -0
- jarvis/jarvis_tools/lsp_get_diagnostics.py +121 -0
- jarvis/jarvis_tools/lsp_get_document_symbols.py +87 -0
- jarvis/jarvis_tools/lsp_prepare_rename.py +130 -0
- jarvis/jarvis_tools/lsp_validate_edit.py +141 -0
- jarvis/{tools → jarvis_tools}/methodology.py +6 -1
- jarvis/{tools → jarvis_tools}/rag.py +1 -1
- jarvis/{tools → jarvis_tools}/read_code.py +0 -31
- jarvis/{tools → jarvis_tools}/registry.py +6 -5
- jarvis/{tools → jarvis_tools}/search.py +2 -2
- jarvis/utils.py +71 -28
- {jarvis_ai_assistant-0.1.103.dist-info → jarvis_ai_assistant-0.1.105.dist-info}/METADATA +98 -62
- jarvis_ai_assistant-0.1.105.dist-info/RECORD +62 -0
- {jarvis_ai_assistant-0.1.103.dist-info → jarvis_ai_assistant-0.1.105.dist-info}/entry_points.txt +4 -4
- jarvis/models/__init__.py +0 -3
- jarvis/tools/code_review.py +0 -163
- jarvis/tools/create_code_sub_agent.py +0 -30
- jarvis/tools/create_code_test_agent.py +0 -115
- jarvis/tools/create_ctags_agent.py +0 -176
- jarvis/tools/find_in_codebase.py +0 -108
- jarvis_ai_assistant-0.1.103.dist-info/RECORD +0 -51
- /jarvis/{models → jarvis_platform}/base.py +0 -0
- /jarvis/{tools → jarvis_platform_manager}/__init__.py +0 -0
- /jarvis/{tools → jarvis_tools}/base.py +0 -0
- /jarvis/{tools → jarvis_tools}/execute_shell.py +0 -0
- /jarvis/{tools → jarvis_tools}/file_operation.py +0 -0
- /jarvis/{tools → jarvis_tools}/read_webpage.py +0 -0
- /jarvis/{tools → jarvis_tools}/select_code_files.py +0 -0
- {jarvis_ai_assistant-0.1.103.dist-info → jarvis_ai_assistant-0.1.105.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.103.dist-info → jarvis_ai_assistant-0.1.105.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.103.dist-info → jarvis_ai_assistant-0.1.105.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
jarvis/agent.py
CHANGED
|
@@ -5,22 +5,29 @@ from typing import Callable, Dict, List, Optional
|
|
|
5
5
|
from prompt_toolkit import prompt
|
|
6
6
|
import yaml
|
|
7
7
|
|
|
8
|
-
from jarvis.
|
|
9
|
-
from jarvis.
|
|
10
|
-
from jarvis.
|
|
11
|
-
from jarvis.utils import PrettyOutput, OutputType, is_auto_complete, load_methodology, add_agent, delete_current_agent, get_max_context_length, get_multiline_input, init_env
|
|
8
|
+
from jarvis.jarvis_platform.base import BasePlatform
|
|
9
|
+
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
10
|
+
from jarvis.jarvis_tools.registry import ToolRegistry, tool_call_help
|
|
11
|
+
from jarvis.utils import PrettyOutput, OutputType, is_auto_complete, is_need_summary, is_record_methodology, load_methodology, add_agent, delete_current_agent, get_max_context_length, get_multiline_input, init_env, is_use_methodology
|
|
12
12
|
import os
|
|
13
13
|
|
|
14
14
|
class Agent:
|
|
15
15
|
|
|
16
|
-
def __del__(self):
|
|
17
|
-
delete_current_agent()
|
|
18
|
-
|
|
19
16
|
def set_summary_prompt(self, summary_prompt: str):
|
|
17
|
+
"""Set the summary prompt for task completion.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
summary_prompt: The prompt template for generating task summaries
|
|
21
|
+
"""
|
|
20
22
|
self.summary_prompt = summary_prompt
|
|
21
23
|
|
|
22
|
-
def
|
|
23
|
-
|
|
24
|
+
def set_output_handler_before_tool(self, handler: List[Callable]):
|
|
25
|
+
"""Set handlers to process output before tool execution.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
handler: List of callable functions to process output
|
|
29
|
+
"""
|
|
30
|
+
self.output_handler_before_tool = handler
|
|
24
31
|
|
|
25
32
|
def __init__(self,
|
|
26
33
|
system_prompt: str,
|
|
@@ -29,35 +36,47 @@ class Agent:
|
|
|
29
36
|
tool_registry: Optional[ToolRegistry] = None,
|
|
30
37
|
platform: Optional[BasePlatform] = None,
|
|
31
38
|
summary_prompt: Optional[str] = None,
|
|
32
|
-
auto_complete: bool =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
auto_complete: Optional[bool] = None,
|
|
40
|
+
output_handler_before_tool: Optional[List[Callable]] = None,
|
|
41
|
+
output_handler_after_tool: Optional[List[Callable]] = None,
|
|
42
|
+
use_methodology: Optional[bool] = None,
|
|
43
|
+
record_methodology: Optional[bool] = None,
|
|
44
|
+
need_summary: Optional[bool] = None,
|
|
45
|
+
max_context_length: Optional[int] = None):
|
|
46
|
+
"""Initialize an Agent instance.
|
|
37
47
|
|
|
38
48
|
Args:
|
|
39
|
-
system_prompt:
|
|
40
|
-
name: Agent name,
|
|
41
|
-
is_sub_agent: Whether
|
|
42
|
-
tool_registry:
|
|
43
|
-
platform:
|
|
49
|
+
system_prompt: The system prompt defining agent behavior
|
|
50
|
+
name: Agent name, defaults to "Jarvis"
|
|
51
|
+
is_sub_agent: Whether this is a sub-agent
|
|
52
|
+
tool_registry: Registry of available tools
|
|
53
|
+
platform: AI platform to use
|
|
54
|
+
summary_prompt: Template for generating summaries
|
|
55
|
+
auto_complete: Whether to enable auto-completion
|
|
56
|
+
output_handler_before_tool: Handlers to process output before tool execution
|
|
57
|
+
output_handler_after_tool: Handlers to process output after tool execution
|
|
58
|
+
use_methodology: Whether to use methodology
|
|
59
|
+
record_methodology: Whether to record methodology
|
|
60
|
+
need_summary: Whether to generate summaries
|
|
61
|
+
max_context_length: Maximum context length
|
|
44
62
|
"""
|
|
45
|
-
add_agent(name)
|
|
46
63
|
PrettyOutput.print(f"Welcome to Jarvis, your AI assistant, Initiating...", OutputType.SYSTEM)
|
|
47
64
|
if platform is not None:
|
|
48
65
|
self.model = platform
|
|
49
66
|
else:
|
|
50
67
|
self.model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
51
68
|
self.tool_registry = tool_registry if tool_registry else ToolRegistry()
|
|
52
|
-
self.record_methodology = record_methodology
|
|
69
|
+
self.record_methodology = record_methodology if record_methodology is not None else is_record_methodology()
|
|
70
|
+
self.use_methodology = use_methodology if use_methodology is not None else is_use_methodology()
|
|
53
71
|
self.name = name
|
|
54
72
|
self.is_sub_agent = is_sub_agent
|
|
55
73
|
self.prompt = ""
|
|
56
74
|
self.conversation_length = 0 # Use length counter instead
|
|
57
75
|
self.system_prompt = system_prompt
|
|
58
|
-
self.need_summary = need_summary
|
|
76
|
+
self.need_summary = need_summary if need_summary is not None else is_need_summary()
|
|
59
77
|
# Load configuration from environment variables
|
|
60
|
-
self.
|
|
78
|
+
self.output_handler_before_tool = output_handler_before_tool if output_handler_before_tool else []
|
|
79
|
+
self.output_handler_after_tool = output_handler_after_tool if output_handler_after_tool else []
|
|
61
80
|
|
|
62
81
|
self.summary_prompt = summary_prompt if summary_prompt else f"""Please generate a concise summary report of the task execution, including:
|
|
63
82
|
|
|
@@ -70,28 +89,22 @@ class Agent:
|
|
|
70
89
|
Please describe in concise bullet points, highlighting important information.
|
|
71
90
|
"""
|
|
72
91
|
|
|
73
|
-
self.max_context_length = get_max_context_length()
|
|
74
|
-
|
|
75
|
-
self.auto_complete = auto_complete
|
|
76
|
-
|
|
92
|
+
self.max_context_length = max_context_length if max_context_length is not None else get_max_context_length()
|
|
77
93
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
# Initialize methodology related attributes
|
|
81
|
-
self.methodology_data = []
|
|
94
|
+
self.auto_complete = auto_complete if auto_complete is not None else is_auto_complete()
|
|
82
95
|
|
|
83
96
|
PrettyOutput.section(f"Jarvis initialized - With {self.model.name()}", OutputType.SYSTEM)
|
|
97
|
+
|
|
84
98
|
tools = self.tool_registry.get_all_tools()
|
|
85
99
|
if tools:
|
|
86
100
|
PrettyOutput.section(f"Available tools: {', '.join([tool['name'] for tool in tools])}", OutputType.SYSTEM)
|
|
87
101
|
|
|
88
|
-
|
|
89
|
-
# Load methodology
|
|
90
102
|
|
|
91
103
|
tools_prompt = self.tool_registry.load_tools()
|
|
92
104
|
complete_prompt = """"""
|
|
93
105
|
if self.auto_complete:
|
|
94
106
|
complete_prompt = """
|
|
107
|
+
## Task Completion
|
|
95
108
|
When the task is completed, you should print the following message:
|
|
96
109
|
<!!!COMPLETE!!!>
|
|
97
110
|
"""
|
|
@@ -106,8 +119,18 @@ Please describe in concise bullet points, highlighting important information.
|
|
|
106
119
|
self.first = True
|
|
107
120
|
|
|
108
121
|
@staticmethod
|
|
109
|
-
def
|
|
110
|
-
"""Extract tool calls from content
|
|
122
|
+
def _extract_tool_calls(content: str) -> List[Dict]:
|
|
123
|
+
"""Extract tool calls from content.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
content: The content containing tool calls
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
List[Dict]: List of extracted tool calls with name and arguments
|
|
130
|
+
|
|
131
|
+
Raises:
|
|
132
|
+
Exception: If tool call is missing necessary fields
|
|
133
|
+
"""
|
|
111
134
|
# Split content into lines
|
|
112
135
|
lines = content.split('\n')
|
|
113
136
|
tool_call_lines = []
|
|
@@ -143,7 +166,17 @@ Please describe in concise bullet points, highlighting important information.
|
|
|
143
166
|
return []
|
|
144
167
|
|
|
145
168
|
def _call_model(self, message: str) -> str:
|
|
146
|
-
"""Call model
|
|
169
|
+
"""Call the AI model with retry logic.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
message: The input message for the model
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
str: Model's response
|
|
176
|
+
|
|
177
|
+
Note:
|
|
178
|
+
Will retry with exponential backoff up to 30 seconds between retries
|
|
179
|
+
"""
|
|
147
180
|
sleep_time = 5
|
|
148
181
|
while True:
|
|
149
182
|
ret = self.model.chat_until_success(message)
|
|
@@ -159,16 +192,17 @@ Please describe in concise bullet points, highlighting important information.
|
|
|
159
192
|
|
|
160
193
|
|
|
161
194
|
def _summarize_and_clear_history(self) -> None:
|
|
162
|
-
"""
|
|
163
|
-
[System message]
|
|
164
|
-
Summarize current conversation history and clear history, only keep system message and summary
|
|
195
|
+
"""Summarize current conversation and clear history.
|
|
165
196
|
|
|
166
197
|
This method will:
|
|
167
|
-
1.
|
|
198
|
+
1. Generate a summary of key information
|
|
168
199
|
2. Clear the conversation history
|
|
169
200
|
3. Keep the system message
|
|
170
|
-
4. Add
|
|
171
|
-
5. Reset
|
|
201
|
+
4. Add summary as new context
|
|
202
|
+
5. Reset conversation length
|
|
203
|
+
|
|
204
|
+
Note:
|
|
205
|
+
Used when context length exceeds maximum
|
|
172
206
|
"""
|
|
173
207
|
# Create a new model instance to summarize, avoid affecting the main conversation
|
|
174
208
|
|
|
@@ -203,10 +237,14 @@ Please continue the task based on the above information.
|
|
|
203
237
|
PrettyOutput.print(f"Failed to summarize conversation history: {str(e)}", OutputType.ERROR)
|
|
204
238
|
|
|
205
239
|
def _complete_task(self) -> str:
|
|
206
|
-
"""Complete task and generate summary
|
|
240
|
+
"""Complete the current task and generate summary if needed.
|
|
207
241
|
|
|
208
242
|
Returns:
|
|
209
243
|
str: Task summary or completion status
|
|
244
|
+
|
|
245
|
+
Note:
|
|
246
|
+
- For main agent: May generate methodology if enabled
|
|
247
|
+
- For sub-agent: May generate summary if enabled
|
|
210
248
|
"""
|
|
211
249
|
PrettyOutput.section("Task completed", OutputType.SUCCESS)
|
|
212
250
|
|
|
@@ -227,7 +265,7 @@ Please continue the task based on the above information.
|
|
|
227
265
|
|
|
228
266
|
# 检查是否包含工具调用
|
|
229
267
|
try:
|
|
230
|
-
tool_calls = Agent.
|
|
268
|
+
tool_calls = Agent._extract_tool_calls(response)
|
|
231
269
|
if tool_calls:
|
|
232
270
|
self.tool_registry.handle_tool_calls(tool_calls)
|
|
233
271
|
except Exception as e:
|
|
@@ -246,17 +284,23 @@ Please continue the task based on the above information.
|
|
|
246
284
|
|
|
247
285
|
|
|
248
286
|
def run(self, user_input: str, file_list: Optional[List[str]] = None) -> str:
|
|
249
|
-
"""Process user input and
|
|
287
|
+
"""Process user input and execute the task.
|
|
250
288
|
|
|
251
289
|
Args:
|
|
252
|
-
user_input: User
|
|
253
|
-
file_list: Optional
|
|
254
|
-
|
|
290
|
+
user_input: User's task description or request
|
|
291
|
+
file_list: Optional list of files to process
|
|
292
|
+
|
|
255
293
|
Returns:
|
|
256
294
|
str: Task summary report
|
|
295
|
+
|
|
296
|
+
Note:
|
|
297
|
+
- Handles context management
|
|
298
|
+
- Processes tool calls
|
|
299
|
+
- Manages conversation flow
|
|
300
|
+
- Supports interactive mode
|
|
257
301
|
"""
|
|
258
302
|
|
|
259
|
-
|
|
303
|
+
add_agent(self.name)
|
|
260
304
|
|
|
261
305
|
try:
|
|
262
306
|
PrettyOutput.section("Preparing environment", OutputType.PLANNING)
|
|
@@ -266,7 +310,7 @@ Please continue the task based on the above information.
|
|
|
266
310
|
# 显示任务开始
|
|
267
311
|
PrettyOutput.section(f"Starting new task: {self.name}", OutputType.PLANNING)
|
|
268
312
|
|
|
269
|
-
if self.first:
|
|
313
|
+
if self.first and self.use_methodology:
|
|
270
314
|
self.prompt = f"{user_input}\n\n{load_methodology(user_input)}"
|
|
271
315
|
self.first = False
|
|
272
316
|
else:
|
|
@@ -289,11 +333,11 @@ Please continue the task based on the above information.
|
|
|
289
333
|
self.prompt = ""
|
|
290
334
|
self.conversation_length += len(current_response)
|
|
291
335
|
|
|
292
|
-
for
|
|
293
|
-
self.prompt +=
|
|
336
|
+
for handler in self.output_handler_before_tool:
|
|
337
|
+
self.prompt += handler(current_response)
|
|
294
338
|
|
|
295
339
|
try:
|
|
296
|
-
result = Agent.
|
|
340
|
+
result = Agent._extract_tool_calls(current_response)
|
|
297
341
|
except Exception as e:
|
|
298
342
|
PrettyOutput.print(f"Tool call error: {str(e)}", OutputType.ERROR)
|
|
299
343
|
self.prompt += f"Tool call error: {str(e)}"
|
|
@@ -303,6 +347,9 @@ Please continue the task based on the above information.
|
|
|
303
347
|
PrettyOutput.print("Executing tool call...", OutputType.PROGRESS)
|
|
304
348
|
tool_result = self.tool_registry.handle_tool_calls(result)
|
|
305
349
|
self.prompt += tool_result
|
|
350
|
+
|
|
351
|
+
for handler in self.output_handler_after_tool:
|
|
352
|
+
self.prompt += handler(current_response)
|
|
306
353
|
|
|
307
354
|
if self.prompt:
|
|
308
355
|
continue
|
|
@@ -328,9 +375,17 @@ Please continue the task based on the above information.
|
|
|
328
375
|
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
329
376
|
return f"Task failed: {str(e)}"
|
|
330
377
|
|
|
378
|
+
finally:
|
|
379
|
+
delete_current_agent()
|
|
331
380
|
|
|
332
|
-
def
|
|
333
|
-
"""Clear conversation history
|
|
381
|
+
def _clear_history(self):
|
|
382
|
+
"""Clear conversation history while preserving system prompt.
|
|
383
|
+
|
|
384
|
+
This will:
|
|
385
|
+
1. Clear the prompt
|
|
386
|
+
2. Reset the model
|
|
387
|
+
3. Reset conversation length counter
|
|
388
|
+
"""
|
|
334
389
|
self.prompt = ""
|
|
335
390
|
self.model.reset()
|
|
336
391
|
self.conversation_length = 0 # Reset conversation length
|
|
@@ -338,7 +393,7 @@ Please continue the task based on the above information.
|
|
|
338
393
|
|
|
339
394
|
|
|
340
395
|
|
|
341
|
-
def
|
|
396
|
+
def _load_tasks() -> dict:
|
|
342
397
|
"""Load tasks from .jarvis files in user home and current directory."""
|
|
343
398
|
tasks = {}
|
|
344
399
|
|
|
@@ -375,18 +430,20 @@ def load_tasks() -> dict:
|
|
|
375
430
|
except Exception as e:
|
|
376
431
|
PrettyOutput.print(f"Error loading .jarvis/pre-command file: {str(e)}", OutputType.ERROR)
|
|
377
432
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
433
|
+
|
|
434
|
+
if is_use_methodology():
|
|
435
|
+
# Read methodology
|
|
436
|
+
method_path = os.path.expanduser("~/.jarvis/methodology")
|
|
437
|
+
if os.path.exists(method_path):
|
|
438
|
+
with open(method_path, "r", encoding="utf-8") as f:
|
|
439
|
+
methodology = yaml.safe_load(f)
|
|
440
|
+
if isinstance(methodology, dict):
|
|
441
|
+
for name, desc in methodology.items():
|
|
442
|
+
tasks[f"Run Methodology: {str(name)}\n {str(desc)}" ] = str(desc)
|
|
386
443
|
|
|
387
444
|
return tasks
|
|
388
445
|
|
|
389
|
-
def
|
|
446
|
+
def _select_task(tasks: dict) -> str:
|
|
390
447
|
"""Let user select a task from the list or skip. Returns task description if selected."""
|
|
391
448
|
if not tasks:
|
|
392
449
|
return ""
|
|
@@ -462,9 +519,9 @@ def main():
|
|
|
462
519
|
agent = Agent(system_prompt=origin_agent_system_prompt, tool_registry=ToolRegistry())
|
|
463
520
|
|
|
464
521
|
# 加载预定义任务
|
|
465
|
-
tasks =
|
|
522
|
+
tasks = _load_tasks()
|
|
466
523
|
if tasks:
|
|
467
|
-
selected_task =
|
|
524
|
+
selected_task = _select_task(tasks)
|
|
468
525
|
if selected_task:
|
|
469
526
|
PrettyOutput.print(f"\nExecute task: {selected_task}", OutputType.INFO)
|
|
470
527
|
agent.run(selected_task, args.files)
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
from enum import auto
|
|
2
1
|
import os
|
|
3
|
-
import re
|
|
4
2
|
from typing import List
|
|
5
3
|
|
|
6
|
-
import yaml
|
|
7
4
|
from jarvis.agent import Agent
|
|
8
5
|
from jarvis.jarvis_code_agent.patch import apply_patch
|
|
9
|
-
from jarvis.jarvis_code_agent.file_select import select_files
|
|
10
6
|
from jarvis.jarvis_code_agent.relevant_files import find_relevant_files
|
|
11
|
-
from jarvis.
|
|
12
|
-
from jarvis.
|
|
13
|
-
from jarvis.
|
|
14
|
-
from jarvis.utils import OutputType, PrettyOutput, get_file_line_count, get_multiline_input,
|
|
7
|
+
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
8
|
+
from jarvis.jarvis_tools.git_commiter import GitCommitTool
|
|
9
|
+
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
10
|
+
from jarvis.utils import OutputType, PrettyOutput, get_file_line_count, get_multiline_input, has_uncommitted_changes, init_env, find_git_root
|
|
15
11
|
|
|
16
12
|
|
|
17
13
|
|
|
@@ -21,7 +17,18 @@ class CodeAgent:
|
|
|
21
17
|
def __init__(self):
|
|
22
18
|
self.root_dir = os.getcwd()
|
|
23
19
|
tool_registry = ToolRegistry()
|
|
24
|
-
tool_registry.use_tools(["read_code",
|
|
20
|
+
tool_registry.use_tools(["read_code",
|
|
21
|
+
"execute_shell",
|
|
22
|
+
"search",
|
|
23
|
+
"create_code_agent",
|
|
24
|
+
"ask_user",
|
|
25
|
+
"ask_codebase",
|
|
26
|
+
"lsp_get_document_symbols",
|
|
27
|
+
"lsp_get_diagnostics",
|
|
28
|
+
"lsp_find_references",
|
|
29
|
+
"lsp_find_definition",
|
|
30
|
+
"lsp_prepare_rename",
|
|
31
|
+
"lsp_validate_edit"])
|
|
25
32
|
code_system_prompt = """
|
|
26
33
|
You are a code agent, you are responsible for modifying the code.
|
|
27
34
|
|
|
@@ -30,23 +37,109 @@ You should read the code and analyze the code, and then provide a plan for the c
|
|
|
30
37
|
## Workflow Steps
|
|
31
38
|
|
|
32
39
|
1. ANALYSIS
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
40
|
+
- Use chain of thought to analyze the requirement:
|
|
41
|
+
```
|
|
42
|
+
Thought: Let me understand what the user is asking for...
|
|
43
|
+
Action: Break down the requirement into specific tasks
|
|
44
|
+
Observation: The key tasks are...
|
|
45
|
+
|
|
46
|
+
Thought: Assess task complexity...
|
|
47
|
+
Action: Evaluate each task's scope and dependencies
|
|
48
|
+
Observation: Task complexity analysis shows...
|
|
49
|
+
|
|
50
|
+
Thought: Determine if task splitting is needed...
|
|
51
|
+
Action: Consider using multiple create_code_agent calls
|
|
52
|
+
Observation: Based on complexity, the approach should be...
|
|
53
|
+
|
|
54
|
+
Conclusion:
|
|
55
|
+
1. Task Breakdown: [list of specific tasks]
|
|
56
|
+
2. Complexity Assessment: [simple/complex]
|
|
57
|
+
3. Development Approach: [single/multiple agents]
|
|
58
|
+
4. Task Dependencies: [dependency order]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
IMPORTANT TASK MANAGEMENT:
|
|
62
|
+
- For complex requirements:
|
|
63
|
+
* Break down into smaller, manageable tasks
|
|
64
|
+
* Use create_code_agent for each sub-task
|
|
65
|
+
* Maintain proper task ordering
|
|
66
|
+
* Ensure integration between sub-tasks
|
|
67
|
+
|
|
68
|
+
Example Task Split:
|
|
69
|
+
```
|
|
70
|
+
1. For complex task "Implement new logging system":
|
|
71
|
+
a. First create_code_agent: "Create basic logging interface"
|
|
72
|
+
b. Second create_code_agent: "Implement file logging backend"
|
|
73
|
+
c. Third create_code_agent: "Add log rotation support"
|
|
74
|
+
|
|
75
|
+
2. Benefits:
|
|
76
|
+
- Focused development for each part
|
|
77
|
+
- Clear progress tracking
|
|
78
|
+
- Easier code review
|
|
79
|
+
- Better error handling
|
|
80
|
+
```
|
|
37
81
|
|
|
38
82
|
2. PLANNING
|
|
39
|
-
- Break down the changes into logical steps
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
83
|
+
- Break down the changes into logical steps using chain of thought:
|
|
84
|
+
```
|
|
85
|
+
Thought: First, let me analyze what needs to be changed...
|
|
86
|
+
Action: Use LSP tools to understand the code structure
|
|
87
|
+
Observation: Found these key components...
|
|
88
|
+
|
|
89
|
+
Thought: Based on the analysis, I need to modify...
|
|
90
|
+
Action: Check dependencies and potential impacts
|
|
91
|
+
Observation: These files will be affected...
|
|
92
|
+
|
|
93
|
+
Thought: Consider previously applied patches...
|
|
94
|
+
Action: Review the changes made so far
|
|
95
|
+
Observation: Previous patches have modified...
|
|
96
|
+
|
|
97
|
+
Thought: The remaining changes should be implemented in this order...
|
|
98
|
+
Plan:
|
|
99
|
+
1. First modify X because... [considering previous changes]
|
|
100
|
+
2. Then update Y to handle... [building on previous patches]
|
|
101
|
+
3. Finally adjust Z to ensure... [maintaining consistency]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
IMPORTANT PATCH GUIDELINES:
|
|
105
|
+
- Track all previously applied patches
|
|
106
|
+
- Base new patches on the updated code state
|
|
107
|
+
- Consider cumulative effects of patches
|
|
108
|
+
- Verify patch locations against current file state
|
|
109
|
+
- Update line numbers based on previous changes
|
|
110
|
+
- Maintain consistency with earlier modifications
|
|
111
|
+
- If unsure about current state, ask for clarification
|
|
43
112
|
|
|
44
113
|
3. IMPLEMENTATION
|
|
45
114
|
For each file that needs changes:
|
|
46
|
-
a.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
115
|
+
a. Code Understanding:
|
|
116
|
+
- Use LSP tools to verify current implementation:
|
|
117
|
+
* lsp_get_document_symbols to see current structure
|
|
118
|
+
* lsp_find_definition to confirm current definitions
|
|
119
|
+
* lsp_find_references to trace current usages
|
|
120
|
+
- Consider effects of previous patches
|
|
121
|
+
- Understand current code state
|
|
122
|
+
- Verify patch locations are still valid
|
|
123
|
+
|
|
124
|
+
b. Change Planning:
|
|
125
|
+
- Plan changes based on current code state
|
|
126
|
+
- Account for previous modifications
|
|
127
|
+
- Ensure compatibility with applied patches
|
|
128
|
+
- Update line numbers if needed
|
|
129
|
+
- Document dependencies on previous changes
|
|
130
|
+
|
|
131
|
+
c. Implementation:
|
|
132
|
+
- Write patches for current code state
|
|
133
|
+
- Reference previous patch effects
|
|
134
|
+
- Maintain consistency with earlier changes
|
|
135
|
+
- Verify patch locations are accurate
|
|
136
|
+
- Consider cumulative impact
|
|
137
|
+
|
|
138
|
+
d. Verification:
|
|
139
|
+
- Verify against current code state
|
|
140
|
+
- Test compatibility with previous patches
|
|
141
|
+
- Check for patch sequence issues
|
|
142
|
+
- Validate cumulative changes
|
|
50
143
|
|
|
51
144
|
## File Reading Guidelines
|
|
52
145
|
|
|
@@ -130,6 +223,24 @@ Note: In this example:
|
|
|
130
223
|
- Use 'execute_shell' for grep/find/ctags operations
|
|
131
224
|
- Use 'search' to search on web
|
|
132
225
|
- Use 'ask_user' when clarification is needed
|
|
226
|
+
- LSP Tools for Code Analysis:
|
|
227
|
+
* lsp_get_document_symbols: Get all symbols in a file
|
|
228
|
+
* lsp_get_diagnostics: Get errors and warnings
|
|
229
|
+
* lsp_find_references: Find all references to a symbol
|
|
230
|
+
* lsp_find_definition: Find symbol definition
|
|
231
|
+
* lsp_prepare_rename: Check if symbol can be renamed
|
|
232
|
+
* lsp_validate_edit: Validate code changes
|
|
233
|
+
Example LSP Usage:
|
|
234
|
+
```
|
|
235
|
+
<TOOL_CALL>
|
|
236
|
+
name: lsp_find_definition
|
|
237
|
+
arguments:
|
|
238
|
+
file_path: src/main.py
|
|
239
|
+
line: 10
|
|
240
|
+
character: 15
|
|
241
|
+
language: python
|
|
242
|
+
</TOOL_CALL>
|
|
243
|
+
```
|
|
133
244
|
|
|
134
245
|
Please proceed with the analysis and implementation following this workflow.
|
|
135
246
|
Start by examining the files and planning your changes.
|
|
@@ -142,7 +253,7 @@ Then provide the necessary patches in the specified format.
|
|
|
142
253
|
tool_registry=tool_registry,
|
|
143
254
|
platform=PlatformRegistry().get_codegen_platform(),
|
|
144
255
|
record_methodology=False,
|
|
145
|
-
|
|
256
|
+
output_handler_after_tool=[apply_patch],
|
|
146
257
|
need_summary=False)
|
|
147
258
|
|
|
148
259
|
|
|
@@ -3,7 +3,7 @@ import re
|
|
|
3
3
|
from typing import Dict, List
|
|
4
4
|
from prompt_toolkit import PromptSession
|
|
5
5
|
from prompt_toolkit.completion import WordCompleter, Completer, Completion
|
|
6
|
-
from jarvis.utils import OutputType, PrettyOutput, get_single_line_input
|
|
6
|
+
from jarvis.utils import OutputType, PrettyOutput, get_single_line_input, user_confirm
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def _parse_file_selection(input_str: str, max_index: int) -> List[int]:
|
|
@@ -135,11 +135,10 @@ def select_files(related_files: List[str], root_dir: str) -> List[str]:
|
|
|
135
135
|
for i, file in enumerate(related_files, 1):
|
|
136
136
|
output += f"[{i}] {file}\n"
|
|
137
137
|
|
|
138
|
-
PrettyOutput.print(output, OutputType.INFO)
|
|
138
|
+
PrettyOutput.print(output, OutputType.INFO, lang="markdown")
|
|
139
139
|
|
|
140
140
|
# Ask the user if they need to adjust the file list
|
|
141
|
-
|
|
142
|
-
if user_input == 'y':
|
|
141
|
+
if user_confirm("Do you need to adjust the file list?", False):
|
|
143
142
|
# Let the user select files
|
|
144
143
|
numbers = get_single_line_input("Please enter the file numbers to include (support: 1,3-6 format, press Enter to keep the current selection)").strip()
|
|
145
144
|
if numbers:
|
|
@@ -150,8 +149,7 @@ def select_files(related_files: List[str], root_dir: str) -> List[str]:
|
|
|
150
149
|
PrettyOutput.print("No valid files selected, keep the current selection", OutputType.WARNING)
|
|
151
150
|
|
|
152
151
|
# Ask if they need to supplement files
|
|
153
|
-
|
|
154
|
-
if user_input == 'y':
|
|
152
|
+
if user_confirm("Do you need to supplement other files?", False):
|
|
155
153
|
# Create file completion session
|
|
156
154
|
session = PromptSession(
|
|
157
155
|
completer=_get_file_completer(root_dir),
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import re
|
|
2
|
-
from typing import Dict, Any, List
|
|
2
|
+
from typing import Dict, Any, List
|
|
3
3
|
import os
|
|
4
|
-
from jarvis.
|
|
5
|
-
from jarvis.
|
|
6
|
-
from jarvis.utils import OutputType, PrettyOutput, has_uncommitted_changes, make_choice_input, user_confirm
|
|
4
|
+
from jarvis.jarvis_tools.git_commiter import GitCommitTool
|
|
5
|
+
from jarvis.utils import OutputType, PrettyOutput, has_uncommitted_changes, user_confirm
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
def _parse_patch(patch_str: str) -> Dict[str, List[Dict[str, Any]]]:
|
|
@@ -60,9 +59,7 @@ def _parse_patch(patch_str: str) -> Dict[str, List[Dict[str, Any]]]:
|
|
|
60
59
|
def apply_patch(output_str: str)->str:
|
|
61
60
|
"""Apply patches to files"""
|
|
62
61
|
patches = _parse_patch(output_str)
|
|
63
|
-
|
|
64
|
-
return ""
|
|
65
|
-
|
|
62
|
+
|
|
66
63
|
for filepath, patch_info in patches.items():
|
|
67
64
|
try:
|
|
68
65
|
# Check if file exists
|
|
@@ -108,6 +105,8 @@ def handle_commit_workflow()->bool:
|
|
|
108
105
|
Returns:
|
|
109
106
|
tuple[bool, str, str]: (continue_execution, commit_id, commit_message)
|
|
110
107
|
"""
|
|
108
|
+
diff = os.popen("git diff HEAD").read()
|
|
109
|
+
PrettyOutput.print(diff, OutputType.CODE, lang="diff")
|
|
111
110
|
if not user_confirm("Do you want to commit the code?", default=True):
|
|
112
111
|
os.system("git reset HEAD")
|
|
113
112
|
os.system("git checkout -- .")
|