jarvis-ai-assistant 0.1.98__py3-none-any.whl → 0.1.99__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 +199 -157
- jarvis/jarvis_code_agent/__init__.py +0 -0
- jarvis/jarvis_code_agent/main.py +203 -0
- jarvis/jarvis_codebase/main.py +412 -284
- jarvis/jarvis_coder/file_select.py +209 -0
- jarvis/jarvis_coder/git_utils.py +64 -2
- jarvis/jarvis_coder/main.py +11 -389
- jarvis/jarvis_coder/patch_handler.py +84 -14
- jarvis/jarvis_coder/plan_generator.py +49 -7
- jarvis/jarvis_rag/main.py +9 -9
- jarvis/jarvis_smart_shell/main.py +5 -7
- jarvis/models/base.py +6 -1
- jarvis/models/ollama.py +2 -2
- jarvis/models/registry.py +3 -6
- jarvis/tools/ask_user.py +6 -6
- jarvis/tools/codebase_qa.py +5 -7
- jarvis/tools/create_code_sub_agent.py +55 -0
- jarvis/tools/{sub_agent.py → create_sub_agent.py} +4 -1
- jarvis/tools/execute_code_modification.py +72 -0
- jarvis/tools/{file_ops.py → file_operation.py} +13 -14
- jarvis/tools/find_related_files.py +86 -0
- jarvis/tools/methodology.py +25 -25
- jarvis/tools/rag.py +32 -32
- jarvis/tools/registry.py +72 -36
- jarvis/tools/search.py +1 -1
- jarvis/tools/select_code_files.py +64 -0
- jarvis/utils.py +153 -49
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/METADATA +1 -1
- jarvis_ai_assistant-0.1.99.dist-info/RECORD +52 -0
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/entry_points.txt +2 -1
- jarvis/main.py +0 -155
- jarvis/tools/coder.py +0 -69
- jarvis_ai_assistant-0.1.98.dist-info/RECORD +0 -47
- /jarvis/tools/{shell.py → execute_shell.py} +0 -0
- /jarvis/tools/{generator.py → generate_tool.py} +0 -0
- /jarvis/tools/{webpage.py → read_webpage.py} +0 -0
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.99.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
jarvis/agent.py
CHANGED
|
@@ -1,32 +1,39 @@
|
|
|
1
|
+
import argparse
|
|
1
2
|
import time
|
|
2
3
|
from typing import Dict, List, Optional
|
|
3
4
|
|
|
5
|
+
from prompt_toolkit import prompt
|
|
4
6
|
import yaml
|
|
5
|
-
import numpy as np
|
|
6
|
-
import faiss
|
|
7
7
|
|
|
8
|
-
from .models.registry import PlatformRegistry
|
|
9
|
-
from .tools import ToolRegistry
|
|
10
|
-
from .
|
|
8
|
+
from jarvis.models.registry import PlatformRegistry
|
|
9
|
+
from jarvis.tools import ToolRegistry
|
|
10
|
+
from jarvis.tools.registry import load_tools
|
|
11
|
+
from jarvis.utils import PrettyOutput, OutputType, get_single_line_input, load_methodology, add_agent, delete_current_agent, get_max_context_length, get_multiline_input, load_embedding_model, load_env_from_file
|
|
11
12
|
import os
|
|
12
13
|
|
|
13
14
|
class Agent:
|
|
14
|
-
|
|
15
|
+
|
|
16
|
+
def __del__(self):
|
|
17
|
+
delete_current_agent()
|
|
18
|
+
|
|
19
|
+
def __init__(self, system_prompt: str, name: str = "Jarvis", is_sub_agent: bool = False, tool_registry: Optional[ToolRegistry] = None):
|
|
15
20
|
"""Initialize Agent with a model, optional tool registry and name
|
|
16
21
|
|
|
17
22
|
Args:
|
|
18
|
-
|
|
19
|
-
tool_registry: Tool registry instance
|
|
23
|
+
system_prompt: System prompt
|
|
20
24
|
name: Agent name, default is "Jarvis"
|
|
21
25
|
is_sub_agent: Whether it is a sub-agent, default is False
|
|
26
|
+
tool_registry: Tool registry instance
|
|
22
27
|
"""
|
|
28
|
+
add_agent(name)
|
|
29
|
+
PrettyOutput.print(f"Welcome to Jarvis, your AI assistant, Initiating...", OutputType.SYSTEM)
|
|
23
30
|
self.model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
24
|
-
self.tool_registry = ToolRegistry.get_global_tool_registry()
|
|
31
|
+
self.tool_registry = tool_registry if tool_registry else ToolRegistry.get_global_tool_registry()
|
|
25
32
|
self.name = name
|
|
26
33
|
self.is_sub_agent = is_sub_agent
|
|
27
34
|
self.prompt = ""
|
|
28
35
|
self.conversation_length = 0 # Use length counter instead
|
|
29
|
-
|
|
36
|
+
self.system_prompt = system_prompt
|
|
30
37
|
# Load configuration from environment variables
|
|
31
38
|
self.embedding_dimension = 1536 # Default for many embedding models
|
|
32
39
|
self.max_context_length = get_max_context_length()
|
|
@@ -46,10 +53,7 @@ class Agent:
|
|
|
46
53
|
PrettyOutput.print("Successfully loaded embedding model", OutputType.SUCCESS)
|
|
47
54
|
|
|
48
55
|
# Initialize HNSW index (use correct dimension)
|
|
49
|
-
|
|
50
|
-
hnsw_index.hnsw.efConstruction = 40
|
|
51
|
-
hnsw_index.hnsw.efSearch = 16
|
|
52
|
-
self.methodology_index = faiss.IndexIDMap(hnsw_index)
|
|
56
|
+
|
|
53
57
|
|
|
54
58
|
except Exception as e:
|
|
55
59
|
PrettyOutput.print(f"Failed to load embedding model: {str(e)}", OutputType.ERROR)
|
|
@@ -58,6 +62,8 @@ class Agent:
|
|
|
58
62
|
# Initialize methodology related attributes
|
|
59
63
|
self.methodology_data = []
|
|
60
64
|
|
|
65
|
+
PrettyOutput.section(f"Jarvis initialized - With {self.model.name()}", OutputType.SYSTEM)
|
|
66
|
+
|
|
61
67
|
@staticmethod
|
|
62
68
|
def extract_tool_calls(content: str) -> List[Dict]:
|
|
63
69
|
"""Extract tool calls from content, if multiple tool calls are detected, raise an exception, and return the content before the tool call and the tool call"""
|
|
@@ -65,7 +71,16 @@ class Agent:
|
|
|
65
71
|
lines = content.split('\n')
|
|
66
72
|
tool_call_lines = []
|
|
67
73
|
in_tool_call = False
|
|
68
|
-
|
|
74
|
+
|
|
75
|
+
tool_call_help = """Tool Usage Format:
|
|
76
|
+
|
|
77
|
+
<TOOL_CALL>
|
|
78
|
+
name: tool_name
|
|
79
|
+
arguments:
|
|
80
|
+
param1: value1
|
|
81
|
+
param2: value2
|
|
82
|
+
</TOOL_CALL>"""
|
|
83
|
+
|
|
69
84
|
# Process line by line
|
|
70
85
|
for line in lines:
|
|
71
86
|
if '<TOOL_CALL>' in line:
|
|
@@ -87,7 +102,7 @@ class Agent:
|
|
|
87
102
|
}]
|
|
88
103
|
else:
|
|
89
104
|
PrettyOutput.print("Tool call missing necessary fields", OutputType.ERROR)
|
|
90
|
-
raise Exception("Tool call missing necessary fields")
|
|
105
|
+
raise Exception("Tool call missing necessary fields, " + tool_call_help)
|
|
91
106
|
except yaml.YAMLError as e:
|
|
92
107
|
PrettyOutput.print(f"YAML parsing error: {str(e)}", OutputType.ERROR)
|
|
93
108
|
raise Exception(f"YAML parsing error: {str(e)}")
|
|
@@ -117,78 +132,6 @@ class Agent:
|
|
|
117
132
|
sleep_time = 30
|
|
118
133
|
continue
|
|
119
134
|
|
|
120
|
-
def _create_methodology_embedding(self, methodology_text: str) -> np.ndarray:
|
|
121
|
-
"""Create embedding vector for methodology text"""
|
|
122
|
-
try:
|
|
123
|
-
# Truncate long text
|
|
124
|
-
max_length = 512
|
|
125
|
-
text = ' '.join(methodology_text.split()[:max_length])
|
|
126
|
-
|
|
127
|
-
# 使用sentence_transformers模型获取嵌入向量
|
|
128
|
-
embedding = self.embedding_model.encode([text],
|
|
129
|
-
convert_to_tensor=True,
|
|
130
|
-
normalize_embeddings=True)
|
|
131
|
-
vector = np.array(embedding.cpu().numpy(), dtype=np.float32)
|
|
132
|
-
return vector[0] # Return first vector, because we only encoded one text
|
|
133
|
-
except Exception as e:
|
|
134
|
-
PrettyOutput.print(f"Failed to create methodology embedding vector: {str(e)}", OutputType.ERROR)
|
|
135
|
-
return np.zeros(self.embedding_dimension, dtype=np.float32)
|
|
136
|
-
|
|
137
|
-
def _load_methodology(self, user_input: str) -> Dict[str, str]:
|
|
138
|
-
"""Load methodology and build vector index"""
|
|
139
|
-
PrettyOutput.print("Loading methodology...", OutputType.PROGRESS)
|
|
140
|
-
user_jarvis_methodology = os.path.expanduser("~/.jarvis_methodology")
|
|
141
|
-
if not os.path.exists(user_jarvis_methodology):
|
|
142
|
-
return {}
|
|
143
|
-
|
|
144
|
-
try:
|
|
145
|
-
with open(user_jarvis_methodology, "r", encoding="utf-8") as f:
|
|
146
|
-
data = yaml.safe_load(f)
|
|
147
|
-
|
|
148
|
-
# Reset data structure
|
|
149
|
-
self.methodology_data = []
|
|
150
|
-
vectors = []
|
|
151
|
-
ids = []
|
|
152
|
-
|
|
153
|
-
# Create embedding vector for each methodology
|
|
154
|
-
for i, (key, value) in enumerate(data.items()):
|
|
155
|
-
PrettyOutput.print(f"Vectorizing methodology: {key} ...", OutputType.INFO)
|
|
156
|
-
methodology_text = f"{key}\n{value}"
|
|
157
|
-
embedding = self._create_methodology_embedding(methodology_text)
|
|
158
|
-
vectors.append(embedding)
|
|
159
|
-
ids.append(i)
|
|
160
|
-
self.methodology_data.append({"key": key, "value": value})
|
|
161
|
-
|
|
162
|
-
if vectors:
|
|
163
|
-
vectors_array = np.vstack(vectors)
|
|
164
|
-
self.methodology_index.add_with_ids(vectors_array, np.array(ids)) # type: ignore
|
|
165
|
-
query_embedding = self._create_methodology_embedding(user_input)
|
|
166
|
-
k = min(5, len(self.methodology_data))
|
|
167
|
-
PrettyOutput.print(f"Retrieving methodology...", OutputType.INFO)
|
|
168
|
-
distances, indices = self.methodology_index.search(
|
|
169
|
-
query_embedding.reshape(1, -1), k
|
|
170
|
-
) # type: ignore
|
|
171
|
-
|
|
172
|
-
relevant_methodologies = {}
|
|
173
|
-
for dist, idx in zip(distances[0], indices[0]):
|
|
174
|
-
if idx >= 0:
|
|
175
|
-
similarity = 1.0 / (1.0 + float(dist))
|
|
176
|
-
methodology = self.methodology_data[idx]
|
|
177
|
-
PrettyOutput.print(
|
|
178
|
-
f"Methodology '{methodology['key']}' similarity: {similarity:.3f}",
|
|
179
|
-
OutputType.INFO
|
|
180
|
-
)
|
|
181
|
-
if similarity >= 0.5:
|
|
182
|
-
relevant_methodologies[methodology["key"]] = methodology["value"]
|
|
183
|
-
|
|
184
|
-
if relevant_methodologies:
|
|
185
|
-
return relevant_methodologies
|
|
186
|
-
|
|
187
|
-
return {}
|
|
188
|
-
|
|
189
|
-
except Exception as e:
|
|
190
|
-
PrettyOutput.print(f"Error loading methodology: {str(e)}", OutputType.ERROR)
|
|
191
|
-
return {}
|
|
192
135
|
|
|
193
136
|
def _summarize_and_clear_history(self) -> None:
|
|
194
137
|
"""
|
|
@@ -244,7 +187,7 @@ Please continue the task based on the above information.
|
|
|
244
187
|
|
|
245
188
|
# 询问是否生成方法论,带输入验证
|
|
246
189
|
while True:
|
|
247
|
-
user_input =
|
|
190
|
+
user_input = get_single_line_input("Generate methodology for this task? (y/n)").strip().lower()
|
|
248
191
|
if user_input in ['y', 'n', '']:
|
|
249
192
|
break
|
|
250
193
|
PrettyOutput.print("Invalid input, please enter y or n", OutputType.WARNING)
|
|
@@ -307,84 +250,20 @@ Please describe in concise bullet points, highlighting important information.
|
|
|
307
250
|
self.model.upload_files(file_list)
|
|
308
251
|
|
|
309
252
|
# Load methodology
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if methodology:
|
|
313
|
-
methodology_prompt = f"""This is the standard methodology for handling previous problems, if the current task is similar, you can refer to it:
|
|
314
|
-
{methodology}
|
|
315
|
-
|
|
316
|
-
"""
|
|
317
|
-
tools_prompt = ""
|
|
318
|
-
|
|
319
|
-
# 选择工具
|
|
320
|
-
PrettyOutput.section("Available tools", OutputType.PLANNING)
|
|
321
|
-
tools = self.tool_registry.get_all_tools()
|
|
322
|
-
if tools:
|
|
323
|
-
tools_prompt += "Available tools:\n"
|
|
324
|
-
for tool in tools:
|
|
325
|
-
PrettyOutput.print(f"{tool['name']}: {tool['description']}", OutputType.INFO)
|
|
326
|
-
tools_prompt += f"- Name: {tool['name']}\n"
|
|
327
|
-
tools_prompt += f" Description: {tool['description']}\n"
|
|
328
|
-
tools_prompt += f" Parameters: {tool['parameters']}\n"
|
|
253
|
+
methodology_prompt = load_methodology(user_input)
|
|
254
|
+
tools_prompt = load_tools()
|
|
329
255
|
|
|
330
256
|
# 显示任务开始
|
|
331
257
|
PrettyOutput.section(f"Starting new task: {self.name}", OutputType.PLANNING)
|
|
332
258
|
|
|
333
259
|
self.clear_history()
|
|
334
260
|
|
|
335
|
-
self.model.set_system_message(f"""
|
|
336
|
-
|
|
337
|
-
When users need to execute tasks, you will strictly follow these steps to handle problems:
|
|
338
|
-
1. Problem Restatement: Confirm understanding of the problem
|
|
339
|
-
2. Root Cause Analysis (only if needed for problem analysis tasks)
|
|
340
|
-
3. Set Objectives: Define achievable and verifiable goals
|
|
341
|
-
4. Generate Solutions: Create one or more actionable solutions
|
|
342
|
-
5. Evaluate Solutions: Select the optimal solution from multiple options
|
|
343
|
-
6. Create Action Plan: Based on available tools, create an action plan using PlantUML format for clear execution flow
|
|
344
|
-
7. Execute Action Plan: Execute one step at a time, **use at most one tool** (wait for tool execution results before proceeding)
|
|
345
|
-
8. Monitor and Adjust: If execution results don't match expectations, reflect and adjust the action plan, iterate previous steps
|
|
346
|
-
9. Methodology: If the current task has general applicability and valuable experience is gained, use methodology tools to record it for future similar problems
|
|
347
|
-
10. Task Completion: End the task using task completion command when finished
|
|
348
|
-
|
|
349
|
-
Methodology Template:
|
|
350
|
-
1. Problem Restatement
|
|
351
|
-
2. Optimal Solution
|
|
352
|
-
3. Optimal Solution Steps (exclude failed actions)
|
|
353
|
-
|
|
354
|
-
-------------------------------------------------------------
|
|
261
|
+
self.model.set_system_message(f"""
|
|
262
|
+
{self.system_prompt}
|
|
355
263
|
|
|
356
264
|
{tools_prompt}
|
|
357
265
|
|
|
358
|
-
-------------------------------------------------------------
|
|
359
|
-
|
|
360
|
-
Tool Usage Format:
|
|
361
|
-
|
|
362
|
-
<TOOL_CALL>
|
|
363
|
-
name: tool_name
|
|
364
|
-
arguments:
|
|
365
|
-
param1: value1
|
|
366
|
-
param2: value2
|
|
367
|
-
</TOOL_CALL>
|
|
368
|
-
|
|
369
|
-
-------------------------------------------------------------
|
|
370
|
-
|
|
371
|
-
Strict Rules:
|
|
372
|
-
- Execute only one tool at a time
|
|
373
|
-
- Tool execution must strictly follow the tool usage format
|
|
374
|
-
- Wait for user to provide execution results
|
|
375
|
-
- Don't assume or imagine results
|
|
376
|
-
- Don't create fake dialogues
|
|
377
|
-
- If current information is insufficient, you may ask the user
|
|
378
|
-
- Not all problem-solving steps are mandatory, skip as appropriate
|
|
379
|
-
- Ask user before executing tools that might damage system or user's codebase
|
|
380
|
-
- Request user guidance when multiple iterations show no progress
|
|
381
|
-
- If yaml string contains colons, wrap the entire string in quotes to avoid yaml parsing errors
|
|
382
|
-
- Use | syntax for multi-line strings in yaml
|
|
383
|
-
|
|
384
266
|
{methodology_prompt}
|
|
385
|
-
|
|
386
|
-
-------------------------------------------------------------
|
|
387
|
-
|
|
388
267
|
""")
|
|
389
268
|
self.prompt = f"{user_input}"
|
|
390
269
|
|
|
@@ -446,3 +325,166 @@ Strict Rules:
|
|
|
446
325
|
|
|
447
326
|
|
|
448
327
|
|
|
328
|
+
|
|
329
|
+
def load_tasks() -> dict:
|
|
330
|
+
"""Load tasks from .jarvis files in user home and current directory."""
|
|
331
|
+
tasks = {}
|
|
332
|
+
|
|
333
|
+
# Check .jarvis in user directory
|
|
334
|
+
user_jarvis = os.path.expanduser("~/.jarvis")
|
|
335
|
+
if os.path.exists(user_jarvis):
|
|
336
|
+
try:
|
|
337
|
+
with open(user_jarvis, "r", encoding="utf-8") as f:
|
|
338
|
+
user_tasks = yaml.safe_load(f)
|
|
339
|
+
|
|
340
|
+
if isinstance(user_tasks, dict):
|
|
341
|
+
# Validate and add user directory tasks
|
|
342
|
+
for name, desc in user_tasks.items():
|
|
343
|
+
if desc: # Ensure description is not empty
|
|
344
|
+
tasks[str(name)] = str(desc)
|
|
345
|
+
else:
|
|
346
|
+
PrettyOutput.print("Warning: ~/.jarvis file should contain a dictionary of task_name: task_description", OutputType.ERROR)
|
|
347
|
+
except Exception as e:
|
|
348
|
+
PrettyOutput.print(f"Error loading ~/.jarvis file: {str(e)}", OutputType.ERROR)
|
|
349
|
+
|
|
350
|
+
# Check .jarvis in current directory
|
|
351
|
+
if os.path.exists(".jarvis"):
|
|
352
|
+
try:
|
|
353
|
+
with open(".jarvis", "r", encoding="utf-8") as f:
|
|
354
|
+
local_tasks = yaml.safe_load(f)
|
|
355
|
+
|
|
356
|
+
if isinstance(local_tasks, dict):
|
|
357
|
+
# Validate and add current directory tasks, overwrite user directory tasks if there is a name conflict
|
|
358
|
+
for name, desc in local_tasks.items():
|
|
359
|
+
if desc: # Ensure description is not empty
|
|
360
|
+
tasks[str(name)] = str(desc)
|
|
361
|
+
else:
|
|
362
|
+
PrettyOutput.print("Warning: .jarvis file should contain a dictionary of task_name: task_description", OutputType.ERROR)
|
|
363
|
+
except Exception as e:
|
|
364
|
+
PrettyOutput.print(f"Error loading .jarvis file: {str(e)}", OutputType.ERROR)
|
|
365
|
+
|
|
366
|
+
# Read methodology
|
|
367
|
+
method_path = os.path.expanduser("~/.jarvis_methodology")
|
|
368
|
+
if os.path.exists(method_path):
|
|
369
|
+
with open(method_path, "r", encoding="utf-8") as f:
|
|
370
|
+
methodology = yaml.safe_load(f)
|
|
371
|
+
if isinstance(methodology, dict):
|
|
372
|
+
for name, desc in methodology.items():
|
|
373
|
+
tasks[f"Run Methodology: {str(name)}\n {str(desc)}" ] = str(desc)
|
|
374
|
+
|
|
375
|
+
return tasks
|
|
376
|
+
|
|
377
|
+
def select_task(tasks: dict) -> str:
|
|
378
|
+
"""Let user select a task from the list or skip. Returns task description if selected."""
|
|
379
|
+
if not tasks:
|
|
380
|
+
return ""
|
|
381
|
+
|
|
382
|
+
# Convert tasks to list for ordered display
|
|
383
|
+
task_names = list(tasks.keys())
|
|
384
|
+
|
|
385
|
+
PrettyOutput.print("\nAvailable tasks:", OutputType.INFO)
|
|
386
|
+
for i, name in enumerate(task_names, 1):
|
|
387
|
+
PrettyOutput.print(f"[{i}] {name}", OutputType.INFO)
|
|
388
|
+
PrettyOutput.print("[0] Skip predefined tasks", OutputType.INFO)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
while True:
|
|
392
|
+
try:
|
|
393
|
+
choice = prompt(
|
|
394
|
+
"\nPlease select a task number (0 to skip): ",
|
|
395
|
+
).strip()
|
|
396
|
+
|
|
397
|
+
if not choice:
|
|
398
|
+
return ""
|
|
399
|
+
|
|
400
|
+
choice = int(choice)
|
|
401
|
+
if choice == 0:
|
|
402
|
+
return ""
|
|
403
|
+
elif 1 <= choice <= len(task_names):
|
|
404
|
+
selected_name = task_names[choice - 1]
|
|
405
|
+
return tasks[selected_name] # Return the task description
|
|
406
|
+
else:
|
|
407
|
+
PrettyOutput.print("Invalid choice. Please select a number from the list.", OutputType.ERROR)
|
|
408
|
+
|
|
409
|
+
except KeyboardInterrupt:
|
|
410
|
+
return "" # Return empty on Ctrl+C
|
|
411
|
+
except EOFError:
|
|
412
|
+
return "" # Return empty on Ctrl+D
|
|
413
|
+
except Exception as e:
|
|
414
|
+
PrettyOutput.print(f"Failed to select task: {str(e)}", OutputType.ERROR)
|
|
415
|
+
continue
|
|
416
|
+
|
|
417
|
+
origin_agent_system_prompt = """You are Jarvis, an AI assistant with powerful problem-solving capabilities.
|
|
418
|
+
|
|
419
|
+
When users need to execute tasks, you will strictly follow these steps to handle problems:
|
|
420
|
+
1. Problem Restatement: Confirm understanding of the problem
|
|
421
|
+
2. Root Cause Analysis (only if needed for problem analysis tasks)
|
|
422
|
+
3. Set Objectives: Define achievable and verifiable goals
|
|
423
|
+
4. Generate Solutions: Create one or more actionable solutions
|
|
424
|
+
5. Evaluate Solutions: Select the optimal solution from multiple options
|
|
425
|
+
6. Create Action Plan: Based on available tools, create an action plan using PlantUML format for clear execution flow
|
|
426
|
+
7. Execute Action Plan: Execute one step at a time, **use at most one tool** (wait for tool execution results before proceeding)
|
|
427
|
+
8. Monitor and Adjust: If execution results don't match expectations, reflect and adjust the action plan, iterate previous steps
|
|
428
|
+
9. Methodology: If the current task has general applicability and valuable experience is gained, use methodology tools to record it for future similar problems
|
|
429
|
+
10. Task Completion: End the task using task completion command when finished
|
|
430
|
+
|
|
431
|
+
Methodology Template:
|
|
432
|
+
1. Problem Restatement
|
|
433
|
+
2. Optimal Solution
|
|
434
|
+
3. Optimal Solution Steps (exclude failed actions)
|
|
435
|
+
|
|
436
|
+
Strict Rules:
|
|
437
|
+
- Execute only one tool at a time
|
|
438
|
+
- Tool execution must strictly follow the tool usage format
|
|
439
|
+
- Wait for user to provide execution results
|
|
440
|
+
- Don't assume or imagine results
|
|
441
|
+
- Don't create fake dialogues
|
|
442
|
+
- If current information is insufficient, you may ask the user
|
|
443
|
+
- Not all problem-solving steps are mandatory, skip as appropriate
|
|
444
|
+
- Ask user before executing tools that might damage system or user's codebase
|
|
445
|
+
- Request user guidance when multiple iterations show no progress
|
|
446
|
+
- If yaml string contains colons, wrap the entire string in quotes to avoid yaml parsing errors
|
|
447
|
+
- Use | syntax for multi-line strings in yaml
|
|
448
|
+
- If you can start executing the task, please start directly without asking the user if you can begin.
|
|
449
|
+
|
|
450
|
+
-------------------------------------------------------------"""
|
|
451
|
+
|
|
452
|
+
def main():
|
|
453
|
+
"""Jarvis main entry point"""
|
|
454
|
+
# Add argument parser
|
|
455
|
+
load_env_from_file()
|
|
456
|
+
parser = argparse.ArgumentParser(description='Jarvis AI assistant')
|
|
457
|
+
parser.add_argument('-f', '--files', nargs='*', help='List of files to process')
|
|
458
|
+
args = parser.parse_args()
|
|
459
|
+
|
|
460
|
+
try:
|
|
461
|
+
# 获取全局模型实例
|
|
462
|
+
agent = Agent(system_prompt=origin_agent_system_prompt)
|
|
463
|
+
|
|
464
|
+
# 加载预定义任务
|
|
465
|
+
tasks = load_tasks()
|
|
466
|
+
if tasks:
|
|
467
|
+
selected_task = select_task(tasks)
|
|
468
|
+
if selected_task:
|
|
469
|
+
PrettyOutput.print(f"\nExecute task: {selected_task}", OutputType.INFO)
|
|
470
|
+
agent.run(selected_task, args.files)
|
|
471
|
+
return 0
|
|
472
|
+
|
|
473
|
+
# 如果没有选择预定义任务,进入交互模式
|
|
474
|
+
while True:
|
|
475
|
+
try:
|
|
476
|
+
user_input = get_multiline_input("Please enter your task (input empty line to exit):")
|
|
477
|
+
if not user_input or user_input == "__interrupt__":
|
|
478
|
+
break
|
|
479
|
+
agent.run(user_input, args.files)
|
|
480
|
+
except Exception as e:
|
|
481
|
+
PrettyOutput.print(f"Error: {str(e)}", OutputType.ERROR)
|
|
482
|
+
|
|
483
|
+
except Exception as e:
|
|
484
|
+
PrettyOutput.print(f"Initialization error: {str(e)}", OutputType.ERROR)
|
|
485
|
+
return 1
|
|
486
|
+
|
|
487
|
+
return 0
|
|
488
|
+
|
|
489
|
+
if __name__ == "__main__":
|
|
490
|
+
exit(main())
|
|
File without changes
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
from jarvis.agent import Agent
|
|
2
|
+
from jarvis.utils import OutputType, PrettyOutput, get_multiline_input, load_env_from_file
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
system_prompt = """You are Jarvis Code Agent, an AI code development assistant specialized in code analysis, modification, and version control. Your role is to help users with coding tasks systematically and reliably.
|
|
8
|
+
|
|
9
|
+
DEVELOPMENT WORKFLOW:
|
|
10
|
+
1. Task Analysis
|
|
11
|
+
- Understand the requirements thoroughly
|
|
12
|
+
- Break down complex tasks into subtasks
|
|
13
|
+
- IMPORTANT: Each subtask should:
|
|
14
|
+
* Modify only ONE file
|
|
15
|
+
* Change no more than 20 lines of code
|
|
16
|
+
* Be focused and atomic
|
|
17
|
+
- Define success criteria
|
|
18
|
+
|
|
19
|
+
2. Code Discovery & Analysis
|
|
20
|
+
- Initial code search:
|
|
21
|
+
* Use shell commands to find patterns:
|
|
22
|
+
<TOOL_CALL>
|
|
23
|
+
name: execute_shell
|
|
24
|
+
arguments:
|
|
25
|
+
command: grep -r 'pattern' directory/
|
|
26
|
+
</TOOL_CALL>
|
|
27
|
+
<TOOL_CALL>
|
|
28
|
+
name: execute_shell
|
|
29
|
+
arguments:
|
|
30
|
+
command: grep -A 5 -B 5 'pattern' file.py
|
|
31
|
+
</TOOL_CALL>
|
|
32
|
+
* Use shell commands to locate files:
|
|
33
|
+
<TOOL_CALL>
|
|
34
|
+
name: execute_shell
|
|
35
|
+
arguments:
|
|
36
|
+
command: find . -name 'pattern'
|
|
37
|
+
</TOOL_CALL>
|
|
38
|
+
* Use shell commands to preview:
|
|
39
|
+
<TOOL_CALL>
|
|
40
|
+
name: execute_shell
|
|
41
|
+
arguments:
|
|
42
|
+
command: head -n 50 file.py
|
|
43
|
+
</TOOL_CALL>
|
|
44
|
+
- File selection and confirmation:
|
|
45
|
+
* Find relevant files:
|
|
46
|
+
<TOOL_CALL>
|
|
47
|
+
name: find_related_files
|
|
48
|
+
arguments:
|
|
49
|
+
query: Need to modify user authentication
|
|
50
|
+
top_k: 5
|
|
51
|
+
</TOOL_CALL>
|
|
52
|
+
* Let user confirm selection:
|
|
53
|
+
<TOOL_CALL>
|
|
54
|
+
name: select_code_files
|
|
55
|
+
arguments:
|
|
56
|
+
related_files:
|
|
57
|
+
- auth.py
|
|
58
|
+
- user.py
|
|
59
|
+
root_dir: .
|
|
60
|
+
</TOOL_CALL>
|
|
61
|
+
- Detailed code examination:
|
|
62
|
+
* Understand code context:
|
|
63
|
+
<TOOL_CALL>
|
|
64
|
+
name: codebase_qa
|
|
65
|
+
arguments:
|
|
66
|
+
query: How does the authentication process work?
|
|
67
|
+
files:
|
|
68
|
+
- auth.py
|
|
69
|
+
</TOOL_CALL>
|
|
70
|
+
|
|
71
|
+
3. Modification Planning
|
|
72
|
+
Generate a detailed modification plan based on user requirements and actual code conditions.
|
|
73
|
+
|
|
74
|
+
4. Code Implementation
|
|
75
|
+
- For small changes (≤20 lines):
|
|
76
|
+
<TOOL_CALL>
|
|
77
|
+
name: execute_code_modification
|
|
78
|
+
arguments:
|
|
79
|
+
task: Add password validation
|
|
80
|
+
structured_plan:
|
|
81
|
+
auth.py: Add password strength check in validate_password()
|
|
82
|
+
</TOOL_CALL>
|
|
83
|
+
- For large changes:
|
|
84
|
+
<TOOL_CALL>
|
|
85
|
+
name: create_code_sub_agent
|
|
86
|
+
arguments:
|
|
87
|
+
subtask: Implement new authentication flow
|
|
88
|
+
codebase_dir: .
|
|
89
|
+
</TOOL_CALL>
|
|
90
|
+
|
|
91
|
+
FILE SELECTION WORKFLOW:
|
|
92
|
+
1. Initial Search
|
|
93
|
+
- Use codebase_search to find relevant files
|
|
94
|
+
- Review search results for relevance
|
|
95
|
+
|
|
96
|
+
2. User Confirmation
|
|
97
|
+
- Use select_code_files to:
|
|
98
|
+
* Display found files
|
|
99
|
+
* Let user review selection
|
|
100
|
+
* Allow file list adjustment
|
|
101
|
+
* Enable file supplementation
|
|
102
|
+
|
|
103
|
+
3. File Validation
|
|
104
|
+
- Verify selected files exist
|
|
105
|
+
- Check file permissions
|
|
106
|
+
- Validate file types
|
|
107
|
+
- Ensure completeness
|
|
108
|
+
|
|
109
|
+
CODE SEARCH BEST PRACTICES:
|
|
110
|
+
- Use grep for pattern matching:
|
|
111
|
+
* grep -r "pattern" directory/
|
|
112
|
+
* grep -A 5 -B 5 for context
|
|
113
|
+
* grep -n for line numbers
|
|
114
|
+
- Use find for file location:
|
|
115
|
+
* find . -name "pattern"
|
|
116
|
+
* find . -type f -exec grep "pattern" {} \\;
|
|
117
|
+
- Use head/tail for previews:
|
|
118
|
+
* head -n 50 file.py
|
|
119
|
+
* tail -n 50 file.py
|
|
120
|
+
* head -n +100 | tail -n 50
|
|
121
|
+
- Avoid loading entire large files
|
|
122
|
+
- Focus on relevant sections
|
|
123
|
+
- Use line numbers for reference
|
|
124
|
+
|
|
125
|
+
SUBTASK MANAGEMENT RULES:
|
|
126
|
+
- One subtask = One file modification
|
|
127
|
+
- Each subtask ≤20 lines of code changes
|
|
128
|
+
- Break down larger changes into multiple subtasks
|
|
129
|
+
- Create separate sub-agent for each subtask
|
|
130
|
+
- Follow dependency order in execution
|
|
131
|
+
- Verify each change independently
|
|
132
|
+
|
|
133
|
+
CODE MODIFICATION LIMITS:
|
|
134
|
+
- Maximum 20 lines per change
|
|
135
|
+
- Count both added and modified lines
|
|
136
|
+
- Exclude comment and blank lines
|
|
137
|
+
- Include only actual code changes
|
|
138
|
+
- Split larger changes into subtasks
|
|
139
|
+
|
|
140
|
+
ITERATION GUIDELINES:
|
|
141
|
+
- Each iteration should be small and focused
|
|
142
|
+
- Keep changes minimal and clear
|
|
143
|
+
- Verify changes before moving forward
|
|
144
|
+
- Document issues and solutions
|
|
145
|
+
- Learn from previous iterations
|
|
146
|
+
|
|
147
|
+
TOOL USAGE:
|
|
148
|
+
1. Analysis Tools:
|
|
149
|
+
- execute_shell: Run grep/find/head/tail commands
|
|
150
|
+
- codebase_search: Find relevant files
|
|
151
|
+
- find_related_files: Find relevant files
|
|
152
|
+
- select_code_files: Confirm and supplement files
|
|
153
|
+
- codebase_qa: Understand context
|
|
154
|
+
- ask_user: Ask user for confirmation and information if needed
|
|
155
|
+
- create_code_sub_agent: Create agent for each small change
|
|
156
|
+
- file_operation: Read files
|
|
157
|
+
- rag: Ask questions based on a document directory, supporting multiple document formats (txt, pdf, docx, etc.)
|
|
158
|
+
- search: Use Bing search engine to search for information, and extract key information based on the question
|
|
159
|
+
- thinker: Deep thinking and logical reasoning
|
|
160
|
+
|
|
161
|
+
2. Planning Tools:
|
|
162
|
+
- thinker: Generate a detailed modification plan based on user requirements and actual code conditions.
|
|
163
|
+
- create_code_sub_agent: Create agent for each small change
|
|
164
|
+
- ask_user: Ask user for confirmation and information if needed
|
|
165
|
+
|
|
166
|
+
3. Implementation Tools:
|
|
167
|
+
- execute_shell: Run shell commands
|
|
168
|
+
- execute_code_modification: Apply small changes (≤20 lines)
|
|
169
|
+
- file_operation: Read, write, or append to files
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
IMPORTANT:
|
|
173
|
+
1. If you can start executing the task, please start directly without asking the user if you can begin.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
def main():
|
|
177
|
+
"""Jarvis main entry point"""
|
|
178
|
+
# Add argument parser
|
|
179
|
+
load_env_from_file()
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
# Get global model instance
|
|
184
|
+
agent = Agent(system_prompt=system_prompt, name="Jarvis Code Agent")
|
|
185
|
+
|
|
186
|
+
# Interactive mode
|
|
187
|
+
while True:
|
|
188
|
+
try:
|
|
189
|
+
user_input = get_multiline_input("Please enter your task (input empty line to exit):")
|
|
190
|
+
if not user_input or user_input == "__interrupt__":
|
|
191
|
+
break
|
|
192
|
+
agent.run(user_input)
|
|
193
|
+
except Exception as e:
|
|
194
|
+
PrettyOutput.print(f"Error: {str(e)}", OutputType.ERROR)
|
|
195
|
+
|
|
196
|
+
except Exception as e:
|
|
197
|
+
PrettyOutput.print(f"Initialization error: {str(e)}", OutputType.ERROR)
|
|
198
|
+
return 1
|
|
199
|
+
|
|
200
|
+
return 0
|
|
201
|
+
|
|
202
|
+
if __name__ == "__main__":
|
|
203
|
+
exit(main())
|