jarvis-ai-assistant 0.1.98__py3-none-any.whl → 0.1.100__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 +202 -0
- jarvis/jarvis_codebase/main.py +415 -287
- jarvis/jarvis_coder/file_select.py +209 -0
- jarvis/jarvis_coder/git_utils.py +64 -2
- jarvis/jarvis_coder/main.py +13 -397
- jarvis/jarvis_coder/patch_handler.py +229 -81
- jarvis/jarvis_coder/plan_generator.py +49 -7
- jarvis/jarvis_platform/main.py +2 -2
- jarvis/jarvis_rag/main.py +11 -11
- jarvis/jarvis_smart_shell/main.py +5 -5
- jarvis/models/base.py +6 -1
- jarvis/models/kimi.py +2 -2
- jarvis/models/ollama.py +2 -2
- jarvis/models/openai.py +1 -1
- jarvis/models/registry.py +38 -18
- jarvis/tools/ask_user.py +12 -9
- jarvis/tools/chdir.py +9 -5
- jarvis/tools/create_code_sub_agent.py +56 -0
- jarvis/tools/{sub_agent.py → create_sub_agent.py} +6 -2
- jarvis/tools/execute_code_modification.py +70 -0
- jarvis/tools/{shell.py → execute_shell.py} +2 -2
- jarvis/tools/{file_ops.py → file_operation.py} +19 -15
- jarvis/tools/find_files.py +119 -0
- jarvis/tools/{generator.py → generate_tool.py} +27 -25
- jarvis/tools/methodology.py +32 -26
- jarvis/tools/rag.py +37 -33
- jarvis/tools/{webpage.py → read_webpage.py} +4 -2
- jarvis/tools/registry.py +94 -48
- jarvis/tools/search.py +19 -16
- jarvis/tools/select_code_files.py +61 -0
- jarvis/tools/thinker.py +7 -5
- jarvis/utils.py +155 -32
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/METADATA +9 -8
- jarvis_ai_assistant-0.1.100.dist-info/RECORD +51 -0
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/entry_points.txt +2 -1
- jarvis/main.py +0 -155
- jarvis/tools/codebase_qa.py +0 -74
- jarvis/tools/coder.py +0 -69
- jarvis_ai_assistant-0.1.98.dist-info/RECORD +0 -47
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.98.dist-info → jarvis_ai_assistant-0.1.100.dist-info}/top_level.txt +0 -0
jarvis/tools/registry.py
CHANGED
|
@@ -10,67 +10,103 @@ from jarvis.tools.base import Tool
|
|
|
10
10
|
from jarvis.utils import OutputType, PrettyOutput, get_max_context_length
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
|
|
14
|
+
def load_tools() -> str:
|
|
15
|
+
"""Load tools"""
|
|
16
|
+
PrettyOutput.section("Available tools", OutputType.PLANNING)
|
|
17
|
+
tools = ToolRegistry.get_global_tool_registry().get_all_tools()
|
|
18
|
+
if tools:
|
|
19
|
+
tools_prompt = "Available tools:\n"
|
|
20
|
+
for tool in tools:
|
|
21
|
+
PrettyOutput.print(f"{tool['name']}: {tool['description']}", OutputType.INFO)
|
|
22
|
+
tools_prompt += f"- Name: {tool['name']}\n"
|
|
23
|
+
tools_prompt += f" Description: {tool['description']}\n"
|
|
24
|
+
tools_prompt += f" Parameters: {tool['parameters']}\n"
|
|
25
|
+
tools_prompt += f" Usage Format: <TOOL_CALL>\n"
|
|
26
|
+
tools_prompt += """
|
|
27
|
+
Tool Usage Format:
|
|
28
|
+
|
|
29
|
+
<TOOL_CALL>
|
|
30
|
+
name: tool_name
|
|
31
|
+
arguments:
|
|
32
|
+
param1: value1
|
|
33
|
+
param2: value2
|
|
34
|
+
</TOOL_CALL>
|
|
35
|
+
---------------------------------------------
|
|
36
|
+
"""
|
|
37
|
+
return tools_prompt
|
|
38
|
+
return ""
|
|
39
|
+
|
|
13
40
|
class ToolRegistry:
|
|
14
41
|
global_tool_registry = None # type: ignore
|
|
15
42
|
def __init__(self):
|
|
16
|
-
"""
|
|
17
|
-
"""
|
|
43
|
+
"""Initialize tool registry"""
|
|
18
44
|
self.tools: Dict[str, Tool] = {}
|
|
19
|
-
#
|
|
45
|
+
# Load built-in tools and external tools
|
|
20
46
|
self._load_builtin_tools()
|
|
21
47
|
self._load_external_tools()
|
|
22
|
-
#
|
|
48
|
+
# Ensure max_context_length is an integer
|
|
23
49
|
self.max_context_length = int(get_max_context_length() * 0.8)
|
|
24
50
|
|
|
51
|
+
def use_tools(self, name: List[str]):
|
|
52
|
+
"""Use specified tools"""
|
|
53
|
+
missing_tools = [tool_name for tool_name in name if tool_name not in self.tools]
|
|
54
|
+
if missing_tools:
|
|
55
|
+
PrettyOutput.print(f"Tools {missing_tools} do not exist, available tools: {', '.join(self.tools.keys())}", OutputType.WARNING)
|
|
56
|
+
self.tools = {tool_name: self.tools[tool_name] for tool_name in name}
|
|
57
|
+
|
|
58
|
+
def dont_use_tools(self, names: List[str]):
|
|
59
|
+
"""Remove specified tools from the registry"""
|
|
60
|
+
self.tools = {name: tool for name, tool in self.tools.items() if name not in names}
|
|
25
61
|
@staticmethod
|
|
26
62
|
def get_global_tool_registry():
|
|
27
|
-
"""
|
|
63
|
+
"""Get the global tool registry"""
|
|
28
64
|
if ToolRegistry.global_tool_registry is None:
|
|
29
65
|
ToolRegistry.global_tool_registry = ToolRegistry()
|
|
30
66
|
return ToolRegistry.global_tool_registry
|
|
31
67
|
|
|
32
68
|
def _load_builtin_tools(self):
|
|
33
|
-
"""
|
|
69
|
+
"""Load tools from the built-in tools directory"""
|
|
34
70
|
tools_dir = Path(__file__).parent
|
|
35
71
|
|
|
36
|
-
#
|
|
72
|
+
# Iterate through all .py files in the directory
|
|
37
73
|
for file_path in tools_dir.glob("*.py"):
|
|
38
|
-
#
|
|
74
|
+
# Skip base.py and __init__.py
|
|
39
75
|
if file_path.name in ["base.py", "__init__.py", "registry.py"]:
|
|
40
76
|
continue
|
|
41
77
|
|
|
42
78
|
self.register_tool_by_file(str(file_path))
|
|
43
79
|
|
|
44
80
|
def _load_external_tools(self):
|
|
45
|
-
"""
|
|
46
|
-
external_tools_dir = Path.home() / '.
|
|
81
|
+
"""Load external tools from ~/.jarvis/tools"""
|
|
82
|
+
external_tools_dir = Path.home() / '.jarvis/tools'
|
|
47
83
|
if not external_tools_dir.exists():
|
|
48
84
|
return
|
|
49
85
|
|
|
50
|
-
#
|
|
86
|
+
# Iterate through all .py files in the directory
|
|
51
87
|
for file_path in external_tools_dir.glob("*.py"):
|
|
52
|
-
#
|
|
88
|
+
# Skip __init__.py
|
|
53
89
|
if file_path.name == "__init__.py":
|
|
54
90
|
continue
|
|
55
91
|
|
|
56
92
|
self.register_tool_by_file(str(file_path))
|
|
57
93
|
|
|
58
94
|
def register_tool_by_file(self, file_path: str):
|
|
59
|
-
"""
|
|
95
|
+
"""Load and register tools from a specified file
|
|
60
96
|
|
|
61
97
|
Args:
|
|
62
|
-
file_path:
|
|
98
|
+
file_path: The path of the tool file
|
|
63
99
|
|
|
64
100
|
Returns:
|
|
65
|
-
bool:
|
|
101
|
+
bool: Whether the tool is loaded successfully
|
|
66
102
|
"""
|
|
67
103
|
try:
|
|
68
|
-
p_file_path = Path(file_path).resolve() #
|
|
104
|
+
p_file_path = Path(file_path).resolve() # Get the absolute path
|
|
69
105
|
if not p_file_path.exists() or not p_file_path.is_file():
|
|
70
106
|
PrettyOutput.print(f"File does not exist: {p_file_path}", OutputType.ERROR)
|
|
71
107
|
return False
|
|
72
108
|
|
|
73
|
-
#
|
|
109
|
+
# Dynamically import the module
|
|
74
110
|
module_name = p_file_path.stem
|
|
75
111
|
spec = importlib.util.spec_from_file_location(module_name, p_file_path) # type: ignore
|
|
76
112
|
if not spec or not spec.loader:
|
|
@@ -78,30 +114,29 @@ class ToolRegistry:
|
|
|
78
114
|
return False
|
|
79
115
|
|
|
80
116
|
module = importlib.util.module_from_spec(spec) # type: ignore
|
|
81
|
-
sys.modules[module_name] = module #
|
|
117
|
+
sys.modules[module_name] = module # Add to sys.modules to support relative imports
|
|
82
118
|
spec.loader.exec_module(module)
|
|
83
119
|
|
|
84
|
-
#
|
|
120
|
+
# Find the tool class in the module
|
|
85
121
|
tool_found = False
|
|
86
122
|
for item_name in dir(module):
|
|
87
123
|
item = getattr(module, item_name)
|
|
88
|
-
#
|
|
124
|
+
# Check if it is a class and has the necessary attributes
|
|
89
125
|
if (isinstance(item, type) and
|
|
90
126
|
hasattr(item, 'name') and
|
|
91
127
|
hasattr(item, 'description') and
|
|
92
128
|
hasattr(item, 'parameters')):
|
|
93
129
|
|
|
94
|
-
#
|
|
130
|
+
# Instantiate the tool class, passing in the model and output processor
|
|
95
131
|
tool_instance = item()
|
|
96
132
|
|
|
97
|
-
#
|
|
133
|
+
# Register the tool
|
|
98
134
|
self.register_tool(
|
|
99
135
|
name=tool_instance.name,
|
|
100
136
|
description=tool_instance.description,
|
|
101
137
|
parameters=tool_instance.parameters,
|
|
102
138
|
func=tool_instance.execute
|
|
103
139
|
)
|
|
104
|
-
PrettyOutput.print(f"Loaded tool from {p_file_path}: {tool_instance.name}: {tool_instance.description}", OutputType.SUCCESS)
|
|
105
140
|
tool_found = True
|
|
106
141
|
break
|
|
107
142
|
|
|
@@ -116,43 +151,54 @@ class ToolRegistry:
|
|
|
116
151
|
return False
|
|
117
152
|
|
|
118
153
|
def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
|
|
119
|
-
"""
|
|
154
|
+
"""Register a new tool"""
|
|
120
155
|
self.tools[name] = Tool(name, description, parameters, func)
|
|
121
156
|
|
|
122
157
|
def get_tool(self, name: str) -> Optional[Tool]:
|
|
123
|
-
"""
|
|
158
|
+
"""Get a tool"""
|
|
124
159
|
return self.tools.get(name)
|
|
125
160
|
|
|
126
161
|
def get_all_tools(self) -> List[Dict]:
|
|
127
|
-
"""
|
|
162
|
+
"""Get all tools in Ollama format definition"""
|
|
128
163
|
return [tool.to_dict() for tool in self.tools.values()]
|
|
129
164
|
|
|
130
165
|
def execute_tool(self, name: str, arguments: Dict) -> Dict[str, Any]:
|
|
131
|
-
"""
|
|
166
|
+
"""Execute a specified tool"""
|
|
132
167
|
tool = self.get_tool(name)
|
|
133
168
|
if tool is None:
|
|
134
|
-
return {"success": False, "
|
|
169
|
+
return {"success": False, "stderr": f"Tool {name} does not exist, available tools: {', '.join(self.tools.keys())}", "stdout": ""}
|
|
135
170
|
return tool.execute(arguments)
|
|
136
171
|
|
|
137
172
|
def handle_tool_calls(self, tool_calls: List[Dict]) -> str:
|
|
138
|
-
"""
|
|
173
|
+
"""Handle tool calls, only process the first tool"""
|
|
139
174
|
try:
|
|
140
175
|
if not tool_calls:
|
|
141
176
|
return ""
|
|
142
177
|
|
|
143
|
-
#
|
|
178
|
+
# Only process the first tool call
|
|
144
179
|
tool_call = tool_calls[0]
|
|
145
180
|
name = tool_call["name"]
|
|
146
181
|
args = tool_call["arguments"]
|
|
182
|
+
|
|
183
|
+
tool_call_help = """
|
|
184
|
+
Tool Usage Format:
|
|
185
|
+
|
|
186
|
+
<TOOL_CALL>
|
|
187
|
+
name: tool_name
|
|
188
|
+
arguments:
|
|
189
|
+
param1: value1
|
|
190
|
+
param2: value2
|
|
191
|
+
</TOOL_CALL>
|
|
192
|
+
"""
|
|
147
193
|
|
|
148
194
|
if isinstance(args, str):
|
|
149
195
|
try:
|
|
150
196
|
args = json.loads(args)
|
|
151
197
|
except json.JSONDecodeError:
|
|
152
|
-
PrettyOutput.print(f"Invalid tool parameters format: {name}", OutputType.ERROR)
|
|
198
|
+
PrettyOutput.print(f"Invalid tool parameters format: {name} {tool_call_help}", OutputType.ERROR)
|
|
153
199
|
return ""
|
|
154
200
|
|
|
155
|
-
#
|
|
201
|
+
# Display tool call information
|
|
156
202
|
PrettyOutput.section(f"Executing tool: {name}", OutputType.TOOL)
|
|
157
203
|
if isinstance(args, dict):
|
|
158
204
|
for key, value in args.items():
|
|
@@ -160,29 +206,31 @@ class ToolRegistry:
|
|
|
160
206
|
else:
|
|
161
207
|
PrettyOutput.print(f"Parameter: {args}", OutputType.DEBUG)
|
|
162
208
|
|
|
163
|
-
#
|
|
209
|
+
# Execute tool call
|
|
164
210
|
result = self.execute_tool(name, args)
|
|
211
|
+
|
|
212
|
+
stdout = result["stdout"]
|
|
213
|
+
stderr = result.get("stderr", "")
|
|
214
|
+
output_parts = []
|
|
215
|
+
if stdout:
|
|
216
|
+
output_parts.append(f"Output:\n{stdout}")
|
|
217
|
+
if stderr:
|
|
218
|
+
output_parts.append(f"Error:\n{stderr}")
|
|
219
|
+
output = "\n\n".join(output_parts)
|
|
220
|
+
output = "no output and error" if not output else output
|
|
165
221
|
|
|
166
|
-
#
|
|
222
|
+
# Process the result
|
|
167
223
|
if result["success"]:
|
|
168
|
-
|
|
169
|
-
stderr = result.get("stderr", "")
|
|
170
|
-
output_parts = []
|
|
171
|
-
if stdout:
|
|
172
|
-
output_parts.append(f"Output:\n{stdout}")
|
|
173
|
-
if stderr:
|
|
174
|
-
output_parts.append(f"Error:\n{stderr}")
|
|
175
|
-
output = "\n\n".join(output_parts)
|
|
176
|
-
output = "No output and error" if not output else output
|
|
224
|
+
|
|
177
225
|
PrettyOutput.section("Execution successful", OutputType.SUCCESS)
|
|
178
226
|
|
|
179
|
-
#
|
|
227
|
+
# If the output exceeds 4k characters, use a large model to summarize
|
|
180
228
|
if len(output) > self.max_context_length:
|
|
181
229
|
try:
|
|
182
230
|
PrettyOutput.print("Output is too long, summarizing...", OutputType.PROGRESS)
|
|
183
231
|
model = PlatformRegistry.get_global_platform_registry().get_normal_platform()
|
|
184
232
|
|
|
185
|
-
#
|
|
233
|
+
# If the output exceeds the maximum context length, only take the last part
|
|
186
234
|
max_len = self.max_context_length
|
|
187
235
|
if len(output) > max_len:
|
|
188
236
|
output_to_summarize = output[-max_len:]
|
|
@@ -215,9 +263,7 @@ Please provide a summary:"""
|
|
|
215
263
|
output = f"Output is too long ({len(output)} characters), it is recommended to view the original output.\nPreview of the first 300 characters:\n{output[:300]}..."
|
|
216
264
|
|
|
217
265
|
else:
|
|
218
|
-
|
|
219
|
-
output = f"Execution failed: {error_msg}"
|
|
220
|
-
PrettyOutput.section("Execution failed", OutputType.ERROR)
|
|
266
|
+
PrettyOutput.section("Execution failed", OutputType.WARNING)
|
|
221
267
|
|
|
222
268
|
return output
|
|
223
269
|
|
jarvis/tools/search.py
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
1
|
from typing import Dict, Any, List
|
|
2
2
|
from jarvis.models.registry import PlatformRegistry
|
|
3
3
|
from jarvis.utils import PrettyOutput, OutputType
|
|
4
|
-
from jarvis.tools.
|
|
4
|
+
from jarvis.tools.read_webpage import WebpageTool
|
|
5
5
|
from playwright.sync_api import sync_playwright
|
|
6
6
|
from urllib.parse import quote
|
|
7
7
|
|
|
8
8
|
def bing_search(query):
|
|
9
9
|
try:
|
|
10
10
|
with sync_playwright() as p:
|
|
11
|
-
#
|
|
11
|
+
# Set parameters when starting the browser
|
|
12
12
|
browser = p.chromium.launch(
|
|
13
|
-
headless=True, #
|
|
13
|
+
headless=True, # Headless mode
|
|
14
14
|
args=['--disable-gpu', '--no-sandbox', '--disable-dev-shm-usage']
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
-
#
|
|
17
|
+
# Create a new page and set timeout
|
|
18
18
|
page = browser.new_page(
|
|
19
19
|
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
|
20
20
|
viewport={'width': 1920, 'height': 1080}
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
-
#
|
|
23
|
+
# Set page timeout
|
|
24
24
|
page.set_default_timeout(60000)
|
|
25
25
|
|
|
26
|
-
#
|
|
26
|
+
# Visit search page
|
|
27
27
|
url = f"https://www.bing.com/search?q={quote(query)}&form=QBLH&sp=-1"
|
|
28
28
|
page.goto(url, wait_until="networkidle")
|
|
29
29
|
|
|
30
|
-
#
|
|
30
|
+
# Wait for search results to load
|
|
31
31
|
page.wait_for_selector("#b_results", state="visible", timeout=30000)
|
|
32
32
|
|
|
33
|
-
#
|
|
33
|
+
# Wait for a moment to ensure the results are fully loaded
|
|
34
34
|
page.wait_for_timeout(1000)
|
|
35
35
|
|
|
36
|
-
#
|
|
36
|
+
# Extract search results
|
|
37
37
|
summaries = page.evaluate("""() => {
|
|
38
38
|
const results = [];
|
|
39
39
|
const elements = document.querySelectorAll("#b_results > .b_algo");
|
|
@@ -96,7 +96,7 @@ class SearchTool:
|
|
|
96
96
|
if not results:
|
|
97
97
|
return []
|
|
98
98
|
|
|
99
|
-
#
|
|
99
|
+
# Format search results
|
|
100
100
|
formatted_results = []
|
|
101
101
|
for result in results[:max_results]:
|
|
102
102
|
formatted_results.append({
|
|
@@ -142,15 +142,16 @@ When answering, pay attention to:
|
|
|
142
142
|
PrettyOutput.print(f"Search query: {query}", OutputType.INFO)
|
|
143
143
|
PrettyOutput.print(f"Related question: {question}", OutputType.INFO)
|
|
144
144
|
|
|
145
|
-
#
|
|
145
|
+
# Get search results
|
|
146
146
|
results = self._search(query, max_results)
|
|
147
147
|
if not results:
|
|
148
148
|
return {
|
|
149
149
|
"success": False,
|
|
150
|
-
"
|
|
150
|
+
"stdout": "",
|
|
151
|
+
"stderr": "No search results found"
|
|
151
152
|
}
|
|
152
153
|
|
|
153
|
-
#
|
|
154
|
+
# Collect webpage content
|
|
154
155
|
contents = []
|
|
155
156
|
for i, result in enumerate(results, 1):
|
|
156
157
|
try:
|
|
@@ -166,7 +167,8 @@ When answering, pay attention to:
|
|
|
166
167
|
if not contents:
|
|
167
168
|
return {
|
|
168
169
|
"success": False,
|
|
169
|
-
"
|
|
170
|
+
"stdout": "",
|
|
171
|
+
"stderr": "No valid search results found"
|
|
170
172
|
}
|
|
171
173
|
|
|
172
174
|
# Extract information
|
|
@@ -182,11 +184,12 @@ When answering, pay attention to:
|
|
|
182
184
|
except Exception as e:
|
|
183
185
|
return {
|
|
184
186
|
"success": False,
|
|
185
|
-
"
|
|
187
|
+
"stdout": "",
|
|
188
|
+
"stderr": f"Search failed: {str(e)}"
|
|
186
189
|
}
|
|
187
190
|
|
|
188
191
|
def main():
|
|
189
|
-
"""
|
|
192
|
+
"""Command line directly run search tool"""
|
|
190
193
|
import argparse
|
|
191
194
|
import sys
|
|
192
195
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from typing import Dict, Any, List
|
|
2
|
+
|
|
3
|
+
from jarvis.utils import OutputType, PrettyOutput
|
|
4
|
+
from jarvis.jarvis_coder.file_select import select_files
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CodeFileSelecterTool:
|
|
8
|
+
name = "select_code_files"
|
|
9
|
+
description = "Select and manage code files for modification with interactive file selection"
|
|
10
|
+
parameters = {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"properties": {
|
|
13
|
+
"related_files": {
|
|
14
|
+
"type": "array",
|
|
15
|
+
"items": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
},
|
|
18
|
+
"description": "List of initially related files",
|
|
19
|
+
"default": []
|
|
20
|
+
},
|
|
21
|
+
"root_dir": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "Root directory of the codebase",
|
|
24
|
+
"default": "."
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"required": ["related_files"]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
31
|
+
"""Execute interactive file selection"""
|
|
32
|
+
try:
|
|
33
|
+
related_files = args["related_files"]
|
|
34
|
+
root_dir = args.get("root_dir", ".")
|
|
35
|
+
|
|
36
|
+
PrettyOutput.print("Starting interactive file selection...", OutputType.INFO)
|
|
37
|
+
|
|
38
|
+
# Use file_select module to handle file selection
|
|
39
|
+
selected_files = select_files(
|
|
40
|
+
related_files=related_files,
|
|
41
|
+
root_dir=root_dir
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Format output for display
|
|
45
|
+
output = "Selected files:\n"
|
|
46
|
+
for file in selected_files:
|
|
47
|
+
output += f"- {file}\n"
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
"success": True,
|
|
51
|
+
"stdout": output,
|
|
52
|
+
"stderr": ""
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
except Exception as e:
|
|
56
|
+
PrettyOutput.print(str(e), OutputType.ERROR)
|
|
57
|
+
return {
|
|
58
|
+
"success": False,
|
|
59
|
+
"stdout": "",
|
|
60
|
+
"stderr": str(e)
|
|
61
|
+
}
|
jarvis/tools/thinker.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from typing import Dict, Any
|
|
2
|
-
from jarvis.utils import OutputType, PrettyOutput,
|
|
2
|
+
from jarvis.utils import OutputType, PrettyOutput, init_env
|
|
3
3
|
from jarvis.models.registry import PlatformRegistry
|
|
4
4
|
|
|
5
5
|
class ThinkerTool:
|
|
@@ -104,7 +104,8 @@ Related context:
|
|
|
104
104
|
if not response:
|
|
105
105
|
return {
|
|
106
106
|
"success": False,
|
|
107
|
-
"
|
|
107
|
+
"stdout": "",
|
|
108
|
+
"stderr": "Failed to obtain valid analysis results"
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
return {
|
|
@@ -117,14 +118,15 @@ Related context:
|
|
|
117
118
|
PrettyOutput.print(f"Thinking analysis failed: {str(e)}", OutputType.ERROR)
|
|
118
119
|
return {
|
|
119
120
|
"success": False,
|
|
120
|
-
"
|
|
121
|
+
"stdout": "",
|
|
122
|
+
"stderr": f"Execution failed: {str(e)}"
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
def main():
|
|
124
126
|
"""Run tool directly from command line"""
|
|
125
127
|
import argparse
|
|
126
128
|
|
|
127
|
-
|
|
129
|
+
init_env()
|
|
128
130
|
|
|
129
131
|
parser = argparse.ArgumentParser(description='Deep thinking analysis tool')
|
|
130
132
|
parser.add_argument('--question', required=True, help='The problem to analyze')
|
|
@@ -143,7 +145,7 @@ def main():
|
|
|
143
145
|
PrettyOutput.print("\nAnalysis results:", OutputType.INFO)
|
|
144
146
|
PrettyOutput.print(result["stdout"], OutputType.INFO)
|
|
145
147
|
else:
|
|
146
|
-
PrettyOutput.print(result["
|
|
148
|
+
PrettyOutput.print(result["stderr"], OutputType.ERROR)
|
|
147
149
|
|
|
148
150
|
if __name__ == "__main__":
|
|
149
151
|
main()
|