jarvis-ai-assistant 0.1.96__py3-none-any.whl → 0.1.98__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 +138 -144
- jarvis/jarvis_codebase/main.py +87 -54
- jarvis/jarvis_coder/git_utils.py +22 -25
- jarvis/jarvis_coder/main.py +166 -171
- jarvis/jarvis_coder/patch_handler.py +153 -453
- jarvis/jarvis_coder/plan_generator.py +76 -48
- jarvis/jarvis_platform/main.py +39 -39
- jarvis/jarvis_rag/main.py +182 -182
- jarvis/jarvis_smart_shell/main.py +34 -34
- jarvis/main.py +24 -24
- jarvis/models/ai8.py +22 -22
- jarvis/models/base.py +17 -13
- jarvis/models/kimi.py +31 -31
- jarvis/models/ollama.py +28 -28
- jarvis/models/openai.py +22 -24
- jarvis/models/oyi.py +25 -25
- jarvis/models/registry.py +33 -34
- jarvis/tools/ask_user.py +5 -5
- jarvis/tools/base.py +2 -2
- jarvis/tools/chdir.py +9 -9
- jarvis/tools/codebase_qa.py +4 -4
- jarvis/tools/coder.py +4 -4
- jarvis/tools/file_ops.py +1 -1
- jarvis/tools/generator.py +23 -23
- jarvis/tools/methodology.py +4 -4
- jarvis/tools/rag.py +4 -4
- jarvis/tools/registry.py +38 -38
- jarvis/tools/search.py +42 -42
- jarvis/tools/shell.py +13 -13
- jarvis/tools/sub_agent.py +16 -16
- jarvis/tools/thinker.py +41 -41
- jarvis/tools/webpage.py +17 -17
- jarvis/utils.py +59 -60
- {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/METADATA +1 -1
- jarvis_ai_assistant-0.1.98.dist-info/RECORD +47 -0
- jarvis_ai_assistant-0.1.96.dist-info/RECORD +0 -47
- {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.96.dist-info → jarvis_ai_assistant-0.1.98.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
jarvis/agent.py
CHANGED
|
@@ -4,73 +4,69 @@ from typing import Dict, List, Optional
|
|
|
4
4
|
import yaml
|
|
5
5
|
import numpy as np
|
|
6
6
|
import faiss
|
|
7
|
-
import json
|
|
8
7
|
|
|
9
8
|
from .models.registry import PlatformRegistry
|
|
10
9
|
from .tools import ToolRegistry
|
|
11
|
-
from .utils import PrettyOutput, OutputType, get_max_context_length, get_multiline_input, load_embedding_model
|
|
10
|
+
from .utils import PrettyOutput, OutputType, get_max_context_length, get_multiline_input, load_embedding_model
|
|
12
11
|
import os
|
|
13
|
-
from datetime import datetime
|
|
14
|
-
from prompt_toolkit import prompt
|
|
15
|
-
from sentence_transformers import SentenceTransformer
|
|
16
12
|
|
|
17
13
|
class Agent:
|
|
18
14
|
def __init__(self, name: str = "Jarvis", is_sub_agent: bool = False):
|
|
19
15
|
"""Initialize Agent with a model, optional tool registry and name
|
|
20
16
|
|
|
21
17
|
Args:
|
|
22
|
-
model:
|
|
23
|
-
tool_registry:
|
|
24
|
-
name: Agent
|
|
25
|
-
is_sub_agent:
|
|
18
|
+
model: LLM model instance
|
|
19
|
+
tool_registry: Tool registry instance
|
|
20
|
+
name: Agent name, default is "Jarvis"
|
|
21
|
+
is_sub_agent: Whether it is a sub-agent, default is False
|
|
26
22
|
"""
|
|
27
23
|
self.model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
28
24
|
self.tool_registry = ToolRegistry.get_global_tool_registry()
|
|
29
25
|
self.name = name
|
|
30
26
|
self.is_sub_agent = is_sub_agent
|
|
31
27
|
self.prompt = ""
|
|
32
|
-
self.conversation_length = 0 #
|
|
28
|
+
self.conversation_length = 0 # Use length counter instead
|
|
33
29
|
|
|
34
|
-
#
|
|
30
|
+
# Load configuration from environment variables
|
|
35
31
|
self.embedding_dimension = 1536 # Default for many embedding models
|
|
36
32
|
self.max_context_length = get_max_context_length()
|
|
37
33
|
|
|
38
|
-
#
|
|
34
|
+
# Initialize embedding model
|
|
39
35
|
try:
|
|
40
36
|
self.embedding_model = load_embedding_model()
|
|
41
37
|
|
|
42
|
-
#
|
|
43
|
-
test_text = "
|
|
38
|
+
# Warm up model and get correct dimension
|
|
39
|
+
test_text = "This is a test text to ensure the model is fully loaded."
|
|
44
40
|
test_embedding = self.embedding_model.encode(
|
|
45
41
|
test_text,
|
|
46
42
|
convert_to_tensor=True,
|
|
47
43
|
normalize_embeddings=True
|
|
48
44
|
)
|
|
49
45
|
self.embedding_dimension = len(test_embedding)
|
|
50
|
-
PrettyOutput.print("
|
|
46
|
+
PrettyOutput.print("Successfully loaded embedding model", OutputType.SUCCESS)
|
|
51
47
|
|
|
52
|
-
#
|
|
48
|
+
# Initialize HNSW index (use correct dimension)
|
|
53
49
|
hnsw_index = faiss.IndexHNSWFlat(self.embedding_dimension, 16)
|
|
54
50
|
hnsw_index.hnsw.efConstruction = 40
|
|
55
51
|
hnsw_index.hnsw.efSearch = 16
|
|
56
52
|
self.methodology_index = faiss.IndexIDMap(hnsw_index)
|
|
57
53
|
|
|
58
54
|
except Exception as e:
|
|
59
|
-
PrettyOutput.print(f"
|
|
55
|
+
PrettyOutput.print(f"Failed to load embedding model: {str(e)}", OutputType.ERROR)
|
|
60
56
|
raise
|
|
61
57
|
|
|
62
|
-
#
|
|
58
|
+
# Initialize methodology related attributes
|
|
63
59
|
self.methodology_data = []
|
|
64
60
|
|
|
65
61
|
@staticmethod
|
|
66
62
|
def extract_tool_calls(content: str) -> List[Dict]:
|
|
67
|
-
"""
|
|
68
|
-
#
|
|
63
|
+
"""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"""
|
|
64
|
+
# Split content into lines
|
|
69
65
|
lines = content.split('\n')
|
|
70
66
|
tool_call_lines = []
|
|
71
67
|
in_tool_call = False
|
|
72
68
|
|
|
73
|
-
#
|
|
69
|
+
# Process line by line
|
|
74
70
|
for line in lines:
|
|
75
71
|
if '<TOOL_CALL>' in line:
|
|
76
72
|
in_tool_call = True
|
|
@@ -78,26 +74,26 @@ class Agent:
|
|
|
78
74
|
elif '</TOOL_CALL>' in line:
|
|
79
75
|
if in_tool_call and tool_call_lines:
|
|
80
76
|
try:
|
|
81
|
-
#
|
|
77
|
+
# Parse YAML directly
|
|
82
78
|
tool_call_text = '\n'.join(tool_call_lines)
|
|
83
79
|
tool_call_data = yaml.safe_load(tool_call_text)
|
|
84
80
|
|
|
85
|
-
#
|
|
81
|
+
# Validate necessary fields
|
|
86
82
|
if "name" in tool_call_data and "arguments" in tool_call_data:
|
|
87
|
-
#
|
|
83
|
+
# Return content before tool call and tool call
|
|
88
84
|
return [{
|
|
89
85
|
"name": tool_call_data["name"],
|
|
90
86
|
"arguments": tool_call_data["arguments"]
|
|
91
87
|
}]
|
|
92
88
|
else:
|
|
93
|
-
PrettyOutput.print("
|
|
94
|
-
raise Exception("
|
|
89
|
+
PrettyOutput.print("Tool call missing necessary fields", OutputType.ERROR)
|
|
90
|
+
raise Exception("Tool call missing necessary fields")
|
|
95
91
|
except yaml.YAMLError as e:
|
|
96
|
-
PrettyOutput.print(f"YAML
|
|
97
|
-
raise Exception(f"YAML
|
|
92
|
+
PrettyOutput.print(f"YAML parsing error: {str(e)}", OutputType.ERROR)
|
|
93
|
+
raise Exception(f"YAML parsing error: {str(e)}")
|
|
98
94
|
except Exception as e:
|
|
99
|
-
PrettyOutput.print(f"
|
|
100
|
-
raise Exception(f"
|
|
95
|
+
PrettyOutput.print(f"Error processing tool call: {str(e)}", OutputType.ERROR)
|
|
96
|
+
raise Exception(f"Error processing tool call: {str(e)}")
|
|
101
97
|
in_tool_call = False
|
|
102
98
|
continue
|
|
103
99
|
|
|
@@ -107,14 +103,14 @@ class Agent:
|
|
|
107
103
|
return []
|
|
108
104
|
|
|
109
105
|
def _call_model(self, message: str) -> str:
|
|
110
|
-
"""
|
|
106
|
+
"""Call model to get response"""
|
|
111
107
|
sleep_time = 5
|
|
112
108
|
while True:
|
|
113
|
-
ret =
|
|
109
|
+
ret = self.model.chat_until_success(message)
|
|
114
110
|
if ret:
|
|
115
111
|
return ret
|
|
116
112
|
else:
|
|
117
|
-
PrettyOutput.print(f"
|
|
113
|
+
PrettyOutput.print(f"Model call failed, retrying... waiting {sleep_time}s", OutputType.INFO)
|
|
118
114
|
time.sleep(sleep_time)
|
|
119
115
|
sleep_time *= 2
|
|
120
116
|
if sleep_time > 30:
|
|
@@ -122,9 +118,9 @@ class Agent:
|
|
|
122
118
|
continue
|
|
123
119
|
|
|
124
120
|
def _create_methodology_embedding(self, methodology_text: str) -> np.ndarray:
|
|
125
|
-
"""
|
|
121
|
+
"""Create embedding vector for methodology text"""
|
|
126
122
|
try:
|
|
127
|
-
#
|
|
123
|
+
# Truncate long text
|
|
128
124
|
max_length = 512
|
|
129
125
|
text = ' '.join(methodology_text.split()[:max_length])
|
|
130
126
|
|
|
@@ -133,14 +129,14 @@ class Agent:
|
|
|
133
129
|
convert_to_tensor=True,
|
|
134
130
|
normalize_embeddings=True)
|
|
135
131
|
vector = np.array(embedding.cpu().numpy(), dtype=np.float32)
|
|
136
|
-
return vector[0] #
|
|
132
|
+
return vector[0] # Return first vector, because we only encoded one text
|
|
137
133
|
except Exception as e:
|
|
138
|
-
PrettyOutput.print(f"
|
|
134
|
+
PrettyOutput.print(f"Failed to create methodology embedding vector: {str(e)}", OutputType.ERROR)
|
|
139
135
|
return np.zeros(self.embedding_dimension, dtype=np.float32)
|
|
140
136
|
|
|
141
137
|
def _load_methodology(self, user_input: str) -> Dict[str, str]:
|
|
142
|
-
"""
|
|
143
|
-
PrettyOutput.print("
|
|
138
|
+
"""Load methodology and build vector index"""
|
|
139
|
+
PrettyOutput.print("Loading methodology...", OutputType.PROGRESS)
|
|
144
140
|
user_jarvis_methodology = os.path.expanduser("~/.jarvis_methodology")
|
|
145
141
|
if not os.path.exists(user_jarvis_methodology):
|
|
146
142
|
return {}
|
|
@@ -149,14 +145,14 @@ class Agent:
|
|
|
149
145
|
with open(user_jarvis_methodology, "r", encoding="utf-8") as f:
|
|
150
146
|
data = yaml.safe_load(f)
|
|
151
147
|
|
|
152
|
-
#
|
|
148
|
+
# Reset data structure
|
|
153
149
|
self.methodology_data = []
|
|
154
150
|
vectors = []
|
|
155
151
|
ids = []
|
|
156
152
|
|
|
157
|
-
#
|
|
153
|
+
# Create embedding vector for each methodology
|
|
158
154
|
for i, (key, value) in enumerate(data.items()):
|
|
159
|
-
PrettyOutput.print(f"
|
|
155
|
+
PrettyOutput.print(f"Vectorizing methodology: {key} ...", OutputType.INFO)
|
|
160
156
|
methodology_text = f"{key}\n{value}"
|
|
161
157
|
embedding = self._create_methodology_embedding(methodology_text)
|
|
162
158
|
vectors.append(embedding)
|
|
@@ -168,7 +164,7 @@ class Agent:
|
|
|
168
164
|
self.methodology_index.add_with_ids(vectors_array, np.array(ids)) # type: ignore
|
|
169
165
|
query_embedding = self._create_methodology_embedding(user_input)
|
|
170
166
|
k = min(5, len(self.methodology_data))
|
|
171
|
-
PrettyOutput.print(f"
|
|
167
|
+
PrettyOutput.print(f"Retrieving methodology...", OutputType.INFO)
|
|
172
168
|
distances, indices = self.methodology_index.search(
|
|
173
169
|
query_embedding.reshape(1, -1), k
|
|
174
170
|
) # type: ignore
|
|
@@ -179,7 +175,7 @@ class Agent:
|
|
|
179
175
|
similarity = 1.0 / (1.0 + float(dist))
|
|
180
176
|
methodology = self.methodology_data[idx]
|
|
181
177
|
PrettyOutput.print(
|
|
182
|
-
f"
|
|
178
|
+
f"Methodology '{methodology['key']}' similarity: {similarity:.3f}",
|
|
183
179
|
OutputType.INFO
|
|
184
180
|
)
|
|
185
181
|
if similarity >= 0.5:
|
|
@@ -191,77 +187,77 @@ class Agent:
|
|
|
191
187
|
return {}
|
|
192
188
|
|
|
193
189
|
except Exception as e:
|
|
194
|
-
PrettyOutput.print(f"
|
|
190
|
+
PrettyOutput.print(f"Error loading methodology: {str(e)}", OutputType.ERROR)
|
|
195
191
|
return {}
|
|
196
192
|
|
|
197
193
|
def _summarize_and_clear_history(self) -> None:
|
|
198
194
|
"""
|
|
199
|
-
[
|
|
200
|
-
|
|
195
|
+
[System message]
|
|
196
|
+
Summarize current conversation history and clear history, only keep system message and summary
|
|
201
197
|
|
|
202
|
-
|
|
203
|
-
1.
|
|
204
|
-
2.
|
|
205
|
-
3.
|
|
206
|
-
4.
|
|
207
|
-
5.
|
|
198
|
+
This method will:
|
|
199
|
+
1. Request the model to summarize the key information from the current conversation
|
|
200
|
+
2. Clear the conversation history
|
|
201
|
+
3. Keep the system message
|
|
202
|
+
4. Add the summary as new context
|
|
203
|
+
5. Reset the conversation round
|
|
208
204
|
"""
|
|
209
|
-
#
|
|
205
|
+
# Create a new model instance to summarize, avoid affecting the main conversation
|
|
210
206
|
|
|
211
|
-
PrettyOutput.print("
|
|
207
|
+
PrettyOutput.print("Summarizing conversation history, preparing to generate summary, starting new conversation...", OutputType.PROGRESS)
|
|
212
208
|
|
|
213
|
-
prompt = """
|
|
214
|
-
1.
|
|
215
|
-
2.
|
|
216
|
-
3.
|
|
217
|
-
4.
|
|
218
|
-
5.
|
|
219
|
-
|
|
220
|
-
|
|
209
|
+
prompt = """Please summarize the key information from the previous conversation, including:
|
|
210
|
+
1. Current task objective
|
|
211
|
+
2. Confirmed key information
|
|
212
|
+
3. Solutions that have been tried
|
|
213
|
+
4. Current progress
|
|
214
|
+
5. Pending issues
|
|
215
|
+
|
|
216
|
+
Please describe in concise bullet points, highlighting important information. Do not include conversation details.
|
|
221
217
|
"""
|
|
222
218
|
|
|
223
219
|
try:
|
|
224
|
-
summary = self.model.
|
|
220
|
+
summary = self.model.chat_until_success(self.prompt + "\n" + prompt)
|
|
225
221
|
|
|
226
222
|
# 清空当前对话历史,但保留系统消息
|
|
227
|
-
self.conversation_length = 0 #
|
|
223
|
+
self.conversation_length = 0 # Reset conversation length
|
|
228
224
|
|
|
229
225
|
# 添加总结作为新的上下文
|
|
230
|
-
self.prompt = f"""
|
|
226
|
+
self.prompt = f"""Here is a summary of key information from previous conversations:
|
|
231
227
|
|
|
232
228
|
{summary}
|
|
233
229
|
|
|
234
|
-
|
|
230
|
+
Please continue the task based on the above information.
|
|
235
231
|
"""
|
|
236
232
|
self.conversation_length = len(self.prompt) # 设置新的起始长度
|
|
237
233
|
|
|
238
234
|
except Exception as e:
|
|
239
|
-
PrettyOutput.print(f"
|
|
235
|
+
PrettyOutput.print(f"Failed to summarize conversation history: {str(e)}", OutputType.ERROR)
|
|
240
236
|
|
|
241
237
|
def _complete_task(self) -> str:
|
|
242
|
-
"""
|
|
238
|
+
"""Complete task and generate summary
|
|
243
239
|
|
|
244
240
|
Returns:
|
|
245
|
-
str:
|
|
241
|
+
str: Task summary or completion status
|
|
246
242
|
"""
|
|
247
|
-
PrettyOutput.section("
|
|
243
|
+
PrettyOutput.section("Task completed", OutputType.SUCCESS)
|
|
248
244
|
|
|
249
245
|
# 询问是否生成方法论,带输入验证
|
|
250
246
|
while True:
|
|
251
|
-
user_input = input("
|
|
247
|
+
user_input = input("Generate methodology for this task? (y/n): ").strip().lower()
|
|
252
248
|
if user_input in ['y', 'n', '']:
|
|
253
249
|
break
|
|
254
|
-
PrettyOutput.print("
|
|
250
|
+
PrettyOutput.print("Invalid input, please enter y or n", OutputType.WARNING)
|
|
255
251
|
|
|
256
252
|
if user_input == 'y':
|
|
257
253
|
try:
|
|
258
254
|
# 让模型判断是否需要生成方法论
|
|
259
|
-
analysis_prompt = """
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
255
|
+
analysis_prompt = """The current task has ended, please analyze whether a methodology needs to be generated.
|
|
256
|
+
If you think a methodology should be generated, first determine whether to create a new methodology or update an existing one. If updating an existing methodology, use 'update', otherwise use 'add'.
|
|
257
|
+
If you think a methodology is not needed, please explain why.
|
|
258
|
+
The methodology should be applicable to general scenarios, do not include task-specific information such as code commit messages.
|
|
259
|
+
The methodology should include: problem restatement, optimal solution, notes (as needed), and nothing else.
|
|
260
|
+
Only output the methodology tool call instruction, or the explanation for not generating a methodology. Do not output anything else.
|
|
265
261
|
"""
|
|
266
262
|
self.prompt = analysis_prompt
|
|
267
263
|
response = self._call_model(self.prompt)
|
|
@@ -270,91 +266,90 @@ class Agent:
|
|
|
270
266
|
try:
|
|
271
267
|
tool_calls = Agent.extract_tool_calls(response)
|
|
272
268
|
if tool_calls:
|
|
273
|
-
|
|
274
|
-
PrettyOutput.print(result, OutputType.RESULT)
|
|
269
|
+
self.tool_registry.handle_tool_calls(tool_calls)
|
|
275
270
|
except Exception as e:
|
|
276
|
-
PrettyOutput.print(f"
|
|
271
|
+
PrettyOutput.print(f"Failed to handle methodology generation: {str(e)}", OutputType.ERROR)
|
|
277
272
|
|
|
278
273
|
except Exception as e:
|
|
279
|
-
PrettyOutput.print(f"
|
|
274
|
+
PrettyOutput.print(f"Error generating methodology: {str(e)}", OutputType.ERROR)
|
|
280
275
|
|
|
281
276
|
if not self.is_sub_agent:
|
|
282
277
|
return "Task completed"
|
|
283
278
|
|
|
284
279
|
# 生成任务总结
|
|
285
|
-
summary_prompt = f"""
|
|
280
|
+
summary_prompt = f"""Please generate a concise summary report of the task execution, including:
|
|
286
281
|
|
|
287
|
-
1.
|
|
288
|
-
2.
|
|
289
|
-
3.
|
|
290
|
-
4.
|
|
291
|
-
5.
|
|
282
|
+
1. Task Objective: Task restatement
|
|
283
|
+
2. Execution Result: Success/Failure
|
|
284
|
+
3. Key Information: Important information extracted during execution
|
|
285
|
+
4. Important Findings: Any noteworthy discoveries
|
|
286
|
+
5. Follow-up Suggestions: If any
|
|
292
287
|
|
|
293
|
-
|
|
288
|
+
Please describe in concise bullet points, highlighting important information.
|
|
294
289
|
"""
|
|
295
290
|
self.prompt = summary_prompt
|
|
296
291
|
return self._call_model(self.prompt)
|
|
297
292
|
|
|
298
293
|
|
|
299
294
|
def run(self, user_input: str, file_list: Optional[List[str]] = None) -> str:
|
|
300
|
-
"""
|
|
295
|
+
"""Process user input and return response, return task summary report
|
|
301
296
|
|
|
302
297
|
Args:
|
|
303
|
-
user_input:
|
|
304
|
-
file_list:
|
|
298
|
+
user_input: User input task description
|
|
299
|
+
file_list: Optional file list, default is None
|
|
305
300
|
|
|
306
301
|
Returns:
|
|
307
|
-
str:
|
|
302
|
+
str: Task summary report
|
|
308
303
|
"""
|
|
309
304
|
try:
|
|
310
|
-
PrettyOutput.section("
|
|
305
|
+
PrettyOutput.section("Preparing environment", OutputType.PLANNING)
|
|
311
306
|
if file_list:
|
|
312
307
|
self.model.upload_files(file_list)
|
|
313
308
|
|
|
314
|
-
#
|
|
309
|
+
# Load methodology
|
|
315
310
|
methodology = self._load_methodology(user_input)
|
|
316
311
|
methodology_prompt = ""
|
|
317
312
|
if methodology:
|
|
318
|
-
methodology_prompt = f"""
|
|
313
|
+
methodology_prompt = f"""This is the standard methodology for handling previous problems, if the current task is similar, you can refer to it:
|
|
319
314
|
{methodology}
|
|
320
315
|
|
|
321
316
|
"""
|
|
322
317
|
tools_prompt = ""
|
|
323
318
|
|
|
324
319
|
# 选择工具
|
|
325
|
-
PrettyOutput.section("
|
|
320
|
+
PrettyOutput.section("Available tools", OutputType.PLANNING)
|
|
326
321
|
tools = self.tool_registry.get_all_tools()
|
|
327
322
|
if tools:
|
|
328
|
-
tools_prompt += "
|
|
323
|
+
tools_prompt += "Available tools:\n"
|
|
329
324
|
for tool in tools:
|
|
330
325
|
PrettyOutput.print(f"{tool['name']}: {tool['description']}", OutputType.INFO)
|
|
331
|
-
tools_prompt += f"-
|
|
332
|
-
tools_prompt += f"
|
|
333
|
-
tools_prompt += f"
|
|
326
|
+
tools_prompt += f"- Name: {tool['name']}\n"
|
|
327
|
+
tools_prompt += f" Description: {tool['description']}\n"
|
|
328
|
+
tools_prompt += f" Parameters: {tool['parameters']}\n"
|
|
334
329
|
|
|
335
330
|
# 显示任务开始
|
|
336
|
-
PrettyOutput.section(f"
|
|
331
|
+
PrettyOutput.section(f"Starting new task: {self.name}", OutputType.PLANNING)
|
|
337
332
|
|
|
338
333
|
self.clear_history()
|
|
339
334
|
|
|
340
|
-
self.model.set_system_message(f"""
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
1.
|
|
344
|
-
2.
|
|
345
|
-
3.
|
|
346
|
-
4.
|
|
347
|
-
5.
|
|
348
|
-
6.
|
|
349
|
-
7.
|
|
350
|
-
8.
|
|
351
|
-
9.
|
|
352
|
-
10.
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
1.
|
|
356
|
-
2.
|
|
357
|
-
3.
|
|
335
|
+
self.model.set_system_message(f"""You are {self.name}, an AI assistant with powerful problem-solving capabilities.
|
|
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)
|
|
358
353
|
|
|
359
354
|
-------------------------------------------------------------
|
|
360
355
|
|
|
@@ -362,7 +357,7 @@ class Agent:
|
|
|
362
357
|
|
|
363
358
|
-------------------------------------------------------------
|
|
364
359
|
|
|
365
|
-
|
|
360
|
+
Tool Usage Format:
|
|
366
361
|
|
|
367
362
|
<TOOL_CALL>
|
|
368
363
|
name: tool_name
|
|
@@ -373,17 +368,18 @@ arguments:
|
|
|
373
368
|
|
|
374
369
|
-------------------------------------------------------------
|
|
375
370
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
|
387
383
|
|
|
388
384
|
{methodology_prompt}
|
|
389
385
|
|
|
@@ -395,7 +391,7 @@ arguments:
|
|
|
395
391
|
while True:
|
|
396
392
|
try:
|
|
397
393
|
# 显示思考状态
|
|
398
|
-
PrettyOutput.print("
|
|
394
|
+
PrettyOutput.print("Analyzing task...", OutputType.PROGRESS)
|
|
399
395
|
|
|
400
396
|
# 累加对话长度
|
|
401
397
|
self.conversation_length += len(self.prompt)
|
|
@@ -406,26 +402,24 @@ arguments:
|
|
|
406
402
|
continue
|
|
407
403
|
else:
|
|
408
404
|
current_response = self._call_model(self.prompt)
|
|
409
|
-
self.conversation_length += len(current_response) #
|
|
405
|
+
self.conversation_length += len(current_response) # Add response length
|
|
410
406
|
try:
|
|
411
407
|
result = Agent.extract_tool_calls(current_response)
|
|
412
408
|
except Exception as e:
|
|
413
|
-
PrettyOutput.print(f"
|
|
414
|
-
self.prompt = f"
|
|
409
|
+
PrettyOutput.print(f"Tool call error: {str(e)}", OutputType.ERROR)
|
|
410
|
+
self.prompt = f"Tool call error: {str(e)}"
|
|
415
411
|
continue
|
|
416
412
|
|
|
417
413
|
if len(result) > 0:
|
|
418
|
-
PrettyOutput.print("
|
|
414
|
+
PrettyOutput.print("Executing tool call...", OutputType.PROGRESS)
|
|
419
415
|
tool_result = self.tool_registry.handle_tool_calls(result)
|
|
420
|
-
PrettyOutput.print(tool_result, OutputType.RESULT)
|
|
421
|
-
|
|
422
416
|
self.prompt = tool_result
|
|
423
417
|
continue
|
|
424
418
|
|
|
425
419
|
# 获取用户输入
|
|
426
|
-
user_input = get_multiline_input(f"{self.name}:
|
|
420
|
+
user_input = get_multiline_input(f"{self.name}: You can continue to input, or enter an empty line to end the current task")
|
|
427
421
|
if user_input == "__interrupt__":
|
|
428
|
-
PrettyOutput.print("
|
|
422
|
+
PrettyOutput.print("Task cancelled by user", OutputType.WARNING)
|
|
429
423
|
return "Task cancelled by user"
|
|
430
424
|
|
|
431
425
|
if user_input:
|
|
@@ -445,10 +439,10 @@ arguments:
|
|
|
445
439
|
|
|
446
440
|
|
|
447
441
|
def clear_history(self):
|
|
448
|
-
"""
|
|
442
|
+
"""Clear conversation history, only keep system prompt"""
|
|
449
443
|
self.prompt = ""
|
|
450
444
|
self.model.reset()
|
|
451
|
-
self.conversation_length = 0 #
|
|
445
|
+
self.conversation_length = 0 # Reset conversation length
|
|
452
446
|
|
|
453
447
|
|
|
454
448
|
|