jarvis-ai-assistant 0.1.102__py3-none-any.whl → 0.1.104__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 -117
- jarvis/jarvis_code_agent/code_agent.py +234 -0
- jarvis/{jarvis_coder → jarvis_code_agent}/file_select.py +19 -22
- jarvis/jarvis_code_agent/patch.py +120 -0
- jarvis/jarvis_code_agent/relevant_files.py +97 -0
- jarvis/jarvis_codebase/main.py +871 -0
- jarvis/jarvis_platform/main.py +5 -3
- jarvis/jarvis_rag/main.py +818 -0
- jarvis/jarvis_smart_shell/main.py +2 -2
- jarvis/models/ai8.py +3 -1
- jarvis/models/kimi.py +36 -30
- jarvis/models/ollama.py +17 -11
- jarvis/models/openai.py +15 -12
- jarvis/models/oyi.py +24 -7
- jarvis/models/registry.py +1 -25
- jarvis/tools/__init__.py +0 -6
- jarvis/tools/ask_codebase.py +96 -0
- jarvis/tools/ask_user.py +1 -9
- jarvis/tools/chdir.py +2 -37
- jarvis/tools/code_review.py +210 -0
- jarvis/tools/create_code_test_agent.py +115 -0
- jarvis/tools/create_ctags_agent.py +164 -0
- jarvis/tools/create_sub_agent.py +2 -2
- jarvis/tools/execute_shell.py +2 -2
- jarvis/tools/file_operation.py +2 -2
- jarvis/tools/find_in_codebase.py +78 -0
- jarvis/tools/git_commiter.py +68 -0
- jarvis/tools/methodology.py +3 -3
- jarvis/tools/rag.py +141 -0
- jarvis/tools/read_code.py +116 -0
- jarvis/tools/read_webpage.py +1 -1
- jarvis/tools/registry.py +47 -31
- jarvis/tools/search.py +8 -6
- jarvis/tools/select_code_files.py +4 -4
- jarvis/utils.py +375 -85
- {jarvis_ai_assistant-0.1.102.dist-info → jarvis_ai_assistant-0.1.104.dist-info}/METADATA +107 -32
- jarvis_ai_assistant-0.1.104.dist-info/RECORD +50 -0
- jarvis_ai_assistant-0.1.104.dist-info/entry_points.txt +11 -0
- jarvis/jarvis_code_agent/main.py +0 -200
- jarvis/jarvis_coder/git_utils.py +0 -123
- jarvis/jarvis_coder/patch_handler.py +0 -340
- jarvis/jarvis_github/main.py +0 -232
- jarvis/tools/create_code_sub_agent.py +0 -56
- jarvis/tools/execute_code_modification.py +0 -70
- jarvis/tools/find_files.py +0 -119
- jarvis/tools/generate_tool.py +0 -174
- jarvis/tools/thinker.py +0 -151
- jarvis_ai_assistant-0.1.102.dist-info/RECORD +0 -46
- jarvis_ai_assistant-0.1.102.dist-info/entry_points.txt +0 -6
- /jarvis/{jarvis_coder → jarvis_codebase}/__init__.py +0 -0
- /jarvis/{jarvis_github → jarvis_rag}/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.102.dist-info → jarvis_ai_assistant-0.1.104.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.102.dist-info → jarvis_ai_assistant-0.1.104.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.102.dist-info → jarvis_ai_assistant-0.1.104.dist-info}/top_level.txt +0 -0
jarvis/tools/methodology.py
CHANGED
|
@@ -73,9 +73,9 @@ class MethodologyTool:
|
|
|
73
73
|
Returns:
|
|
74
74
|
Dict[str, Any]: A dictionary containing the execution result
|
|
75
75
|
"""
|
|
76
|
-
operation = args.get("operation")
|
|
77
|
-
problem_type = args.get("problem_type")
|
|
78
|
-
content = args.get("content")
|
|
76
|
+
operation = args.get("operation", "").strip()
|
|
77
|
+
problem_type = args.get("problem_type", "").strip()
|
|
78
|
+
content = args.get("content", "").strip()
|
|
79
79
|
|
|
80
80
|
if not operation or not problem_type:
|
|
81
81
|
return {
|
jarvis/tools/rag.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from typing import Dict, Any
|
|
2
|
+
import os
|
|
3
|
+
from jarvis.utils import OutputType, PrettyOutput, dont_use_local_model
|
|
4
|
+
from jarvis.jarvis_rag.main import RAGTool as RAGCore
|
|
5
|
+
|
|
6
|
+
class RAGTool:
|
|
7
|
+
name = "rag"
|
|
8
|
+
description = "Ask questions based on a document directory, supporting multiple document formats (txt, pdf, docx, etc.)"
|
|
9
|
+
parameters = {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"properties": {
|
|
12
|
+
"dir": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "Document directory path, supports both relative and absolute paths"
|
|
15
|
+
},
|
|
16
|
+
"question": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "The question to ask"
|
|
19
|
+
},
|
|
20
|
+
"rebuild_index": {
|
|
21
|
+
"type": "boolean",
|
|
22
|
+
"description": "Whether to rebuild the index",
|
|
23
|
+
"default": False
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"required": ["dir", "question"]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def check() -> bool:
|
|
31
|
+
return not dont_use_local_model()
|
|
32
|
+
|
|
33
|
+
def __init__(self):
|
|
34
|
+
"""Initialize RAG tool"""
|
|
35
|
+
self.rag_instances = {} # Cache RAG instances for different directories
|
|
36
|
+
|
|
37
|
+
def _get_rag_instance(self, dir_path: str) -> RAGCore:
|
|
38
|
+
"""Get or create RAG instance
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
dir_path: The absolute path of the document directory
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
RAGCore: RAG instance
|
|
45
|
+
"""
|
|
46
|
+
if dir_path not in self.rag_instances:
|
|
47
|
+
self.rag_instances[dir_path] = RAGCore(dir_path)
|
|
48
|
+
return self.rag_instances[dir_path]
|
|
49
|
+
|
|
50
|
+
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
51
|
+
"""Execute document question and answer
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
args: A dictionary containing parameters
|
|
55
|
+
- dir: The document directory path
|
|
56
|
+
- question: The question to ask
|
|
57
|
+
- rebuild_index: Whether to rebuild the index
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Dict[str, Any]: The execution result
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
# Get parameters
|
|
64
|
+
dir_path = os.path.expanduser(args["dir"]) # Expand ~ paths
|
|
65
|
+
dir_path = os.path.abspath(dir_path) # Convert to absolute path
|
|
66
|
+
question = args["question"]
|
|
67
|
+
rebuild_index = args.get("rebuild_index", False)
|
|
68
|
+
|
|
69
|
+
# Check if the directory exists
|
|
70
|
+
if not os.path.exists(dir_path):
|
|
71
|
+
return {
|
|
72
|
+
"success": False,
|
|
73
|
+
"stdout": "",
|
|
74
|
+
"stderr": f"Directory does not exist: {dir_path}"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# Check if it is a directory
|
|
78
|
+
if not os.path.isdir(dir_path):
|
|
79
|
+
return {
|
|
80
|
+
"success": False,
|
|
81
|
+
"stdout": "",
|
|
82
|
+
"stderr": f"The path is not a directory: {dir_path}"
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# Get RAG instance
|
|
86
|
+
rag = self._get_rag_instance(dir_path)
|
|
87
|
+
|
|
88
|
+
# If you need to rebuild the index or the index does not exist
|
|
89
|
+
if rebuild_index or not rag.is_index_built():
|
|
90
|
+
PrettyOutput.print("Building document index...", OutputType.INFO)
|
|
91
|
+
rag.build_index(dir_path)
|
|
92
|
+
|
|
93
|
+
# Execute question and answer
|
|
94
|
+
PrettyOutput.print(f"Question: {question}", OutputType.INFO)
|
|
95
|
+
response = rag.ask(question)
|
|
96
|
+
|
|
97
|
+
if response is None:
|
|
98
|
+
return {
|
|
99
|
+
"success": False,
|
|
100
|
+
"stdout": "",
|
|
101
|
+
"stderr": "Failed to get answer, possibly no relevant documents found"
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
"success": True,
|
|
106
|
+
"stdout": response,
|
|
107
|
+
"stderr": ""
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
except Exception as e:
|
|
111
|
+
PrettyOutput.print(f"Document question and answer failed: {str(e)}", OutputType.ERROR)
|
|
112
|
+
return {
|
|
113
|
+
"success": False,
|
|
114
|
+
"stdout": "",
|
|
115
|
+
"stderr": f"Execution failed: {str(e)}"
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
def main():
|
|
119
|
+
"""Run the tool directly from the command line"""
|
|
120
|
+
import argparse
|
|
121
|
+
|
|
122
|
+
parser = argparse.ArgumentParser(description='Document question and answer tool')
|
|
123
|
+
parser.add_argument('--dir', required=True, help='Document directory path')
|
|
124
|
+
parser.add_argument('--question', required=True, help='The question to ask')
|
|
125
|
+
parser.add_argument('--rebuild', action='store_true', help='Rebuild index')
|
|
126
|
+
args = parser.parse_args()
|
|
127
|
+
|
|
128
|
+
tool = RAGTool()
|
|
129
|
+
result = tool.execute({
|
|
130
|
+
"dir": args.dir,
|
|
131
|
+
"question": args.question,
|
|
132
|
+
"rebuild_index": args.rebuild
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
if result["success"]:
|
|
136
|
+
PrettyOutput.print(f"{result['stdout']}", OutputType.INFO, lang="markdown")
|
|
137
|
+
else:
|
|
138
|
+
PrettyOutput.print(result["stderr"], OutputType.ERROR)
|
|
139
|
+
|
|
140
|
+
if __name__ == "__main__":
|
|
141
|
+
main()
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from typing import Dict, Any
|
|
2
|
+
import os
|
|
3
|
+
from jarvis.utils import OutputType, PrettyOutput
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ReadCodeTool:
|
|
7
|
+
"""Read code file with line numbers"""
|
|
8
|
+
|
|
9
|
+
name = "read_code"
|
|
10
|
+
description = "Read code file with line numbers"
|
|
11
|
+
parameters = {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"properties": {
|
|
14
|
+
"filepath": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Absolute or relative path to the file"
|
|
17
|
+
},
|
|
18
|
+
"start_line": {
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"description": "Start line number (0-based, inclusive)",
|
|
21
|
+
"default": 0
|
|
22
|
+
},
|
|
23
|
+
"end_line": {
|
|
24
|
+
"type": "integer",
|
|
25
|
+
"description": "End line number (0-based, exclusive). -1 means read to end",
|
|
26
|
+
"default": -1
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"required": ["filepath"]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
33
|
+
"""Execute code reading with line numbers
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
args: Dictionary containing:
|
|
37
|
+
- filepath: Path to the file
|
|
38
|
+
- start_line: Start line number (optional)
|
|
39
|
+
- end_line: End line number (optional)
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Dict containing:
|
|
43
|
+
- success: Boolean indicating success
|
|
44
|
+
- stdout: File content with line numbers
|
|
45
|
+
- stderr: Error message if any
|
|
46
|
+
"""
|
|
47
|
+
try:
|
|
48
|
+
filepath = args["filepath"].strip()
|
|
49
|
+
start_line = args.get("start_line", 0)
|
|
50
|
+
end_line = args.get("end_line", -1)
|
|
51
|
+
|
|
52
|
+
# Record the operation and the full path
|
|
53
|
+
abs_path = os.path.abspath(filepath)
|
|
54
|
+
PrettyOutput.print(f"Reading code file: {abs_path}", OutputType.INFO)
|
|
55
|
+
|
|
56
|
+
# Check if file exists
|
|
57
|
+
if not os.path.exists(filepath):
|
|
58
|
+
return {
|
|
59
|
+
"success": False,
|
|
60
|
+
"stdout": "",
|
|
61
|
+
"stderr": f"File does not exist: {filepath}"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# Check file size
|
|
65
|
+
if os.path.getsize(filepath) > 10 * 1024 * 1024: # 10MB
|
|
66
|
+
return {
|
|
67
|
+
"success": False,
|
|
68
|
+
"stdout": "",
|
|
69
|
+
"stderr": "File too large (>10MB)"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# Read file content
|
|
73
|
+
try:
|
|
74
|
+
with open(filepath, 'r', encoding='utf-8') as f:
|
|
75
|
+
lines = f.readlines()
|
|
76
|
+
except UnicodeDecodeError:
|
|
77
|
+
return {
|
|
78
|
+
"success": False,
|
|
79
|
+
"stdout": "",
|
|
80
|
+
"stderr": "Failed to decode file with UTF-8 encoding"
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# Validate line range
|
|
84
|
+
if start_line < 0:
|
|
85
|
+
start_line = 0
|
|
86
|
+
if end_line == -1 or end_line > len(lines):
|
|
87
|
+
end_line = len(lines)
|
|
88
|
+
if start_line >= end_line:
|
|
89
|
+
return {
|
|
90
|
+
"success": False,
|
|
91
|
+
"stdout": "",
|
|
92
|
+
"stderr": f"Invalid line range: [{start_line}, {end_line})"
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# Format lines with hexadecimal line numbers
|
|
96
|
+
formatted_lines = []
|
|
97
|
+
for i, line in enumerate(lines[start_line:end_line]):
|
|
98
|
+
line_num = start_line + i
|
|
99
|
+
formatted_lines.append(f"{line_num:>5}:{line}")
|
|
100
|
+
|
|
101
|
+
content = "".join(formatted_lines)
|
|
102
|
+
|
|
103
|
+
PrettyOutput.print(f"File: {filepath}\nLines: [{start_line}, {end_line})\n{content}", OutputType.CODE)
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
"success": True,
|
|
107
|
+
"stdout": content,
|
|
108
|
+
"stderr": ""
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
except Exception as e:
|
|
112
|
+
return {
|
|
113
|
+
"success": False,
|
|
114
|
+
"stdout": "",
|
|
115
|
+
"stderr": f"Failed to read code: {str(e)}"
|
|
116
|
+
}
|
jarvis/tools/read_webpage.py
CHANGED
jarvis/tools/registry.py
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import importlib
|
|
2
1
|
import json
|
|
3
|
-
import os
|
|
4
2
|
from pathlib import Path
|
|
5
3
|
import sys
|
|
6
4
|
from typing import Any, Callable, Dict, List, Optional
|
|
@@ -10,20 +8,7 @@ from jarvis.tools.base import Tool
|
|
|
10
8
|
from jarvis.utils import OutputType, PrettyOutput, get_max_context_length
|
|
11
9
|
|
|
12
10
|
|
|
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 += """
|
|
26
|
-
Tool Usage Format:
|
|
11
|
+
tool_call_help = """Tool Usage Format:
|
|
27
12
|
|
|
28
13
|
<TOOL_CALL>
|
|
29
14
|
name: tool_name
|
|
@@ -31,13 +16,48 @@ arguments:
|
|
|
31
16
|
param1: value1
|
|
32
17
|
param2: value2
|
|
33
18
|
</TOOL_CALL>
|
|
34
|
-
|
|
19
|
+
|
|
20
|
+
Strict Rules:
|
|
21
|
+
- Execute only one tool at a time
|
|
22
|
+
- Tool execution must strictly follow the tool usage format
|
|
23
|
+
- Wait for user to provide execution results
|
|
24
|
+
- Don't assume or imagine results
|
|
25
|
+
- Don't create fake dialogues
|
|
26
|
+
- If current information is insufficient, you may ask the user for more information
|
|
27
|
+
- Not all problem-solving steps are mandatory, skip as appropriate
|
|
28
|
+
- Request user guidance when multiple iterations show no progress
|
|
29
|
+
- ALWAYS use | syntax for string parameters to prevent parsing errors
|
|
30
|
+
Example:
|
|
31
|
+
<TOOL_CALL>
|
|
32
|
+
name: execute_shell
|
|
33
|
+
arguments:
|
|
34
|
+
command: |
|
|
35
|
+
git status --porcelain
|
|
36
|
+
</TOOL_CALL>
|
|
37
|
+
<TOOL_CALL>
|
|
38
|
+
name: execute_shell
|
|
39
|
+
arguments:
|
|
40
|
+
command: |
|
|
41
|
+
git commit -m "fix bug"
|
|
42
|
+
</TOOL_CALL>
|
|
43
|
+
|
|
44
|
+
- If you can start executing the task, please start directly without asking the user if you can begin.
|
|
35
45
|
"""
|
|
36
|
-
return tools_prompt
|
|
37
|
-
return ""
|
|
38
46
|
|
|
39
47
|
class ToolRegistry:
|
|
40
|
-
|
|
48
|
+
def load_tools(self) -> str:
|
|
49
|
+
"""Load tools"""
|
|
50
|
+
tools = self.get_all_tools()
|
|
51
|
+
if tools:
|
|
52
|
+
tools_prompt = "Available tools:\n"
|
|
53
|
+
for tool in tools:
|
|
54
|
+
tools_prompt += f"- Name: {tool['name']}\n"
|
|
55
|
+
tools_prompt += f" Description: {tool['description']}\n"
|
|
56
|
+
tools_prompt += f" Parameters: {tool['parameters']}\n"
|
|
57
|
+
tools_prompt += tool_call_help
|
|
58
|
+
return tools_prompt
|
|
59
|
+
return ""
|
|
60
|
+
|
|
41
61
|
def __init__(self):
|
|
42
62
|
"""Initialize tool registry"""
|
|
43
63
|
self.tools: Dict[str, Tool] = {}
|
|
@@ -57,12 +77,6 @@ class ToolRegistry:
|
|
|
57
77
|
def dont_use_tools(self, names: List[str]):
|
|
58
78
|
"""Remove specified tools from the registry"""
|
|
59
79
|
self.tools = {name: tool for name, tool in self.tools.items() if name not in names}
|
|
60
|
-
@staticmethod
|
|
61
|
-
def get_global_tool_registry():
|
|
62
|
-
"""Get the global tool registry"""
|
|
63
|
-
if ToolRegistry.global_tool_registry is None:
|
|
64
|
-
ToolRegistry.global_tool_registry = ToolRegistry()
|
|
65
|
-
return ToolRegistry.global_tool_registry
|
|
66
80
|
|
|
67
81
|
def _load_builtin_tools(self):
|
|
68
82
|
"""Load tools from the built-in tools directory"""
|
|
@@ -126,7 +140,6 @@ class ToolRegistry:
|
|
|
126
140
|
|
|
127
141
|
if hasattr(item, "check"):
|
|
128
142
|
if not item.check():
|
|
129
|
-
PrettyOutput.print(f"Tool {item.name} check failed, skipping", OutputType.INFO)
|
|
130
143
|
continue
|
|
131
144
|
|
|
132
145
|
# Instantiate the tool class
|
|
@@ -143,7 +156,6 @@ class ToolRegistry:
|
|
|
143
156
|
break
|
|
144
157
|
|
|
145
158
|
if not tool_found:
|
|
146
|
-
PrettyOutput.print(f"No valid tool class found in the file: {p_file_path}", OutputType.INFO)
|
|
147
159
|
return False
|
|
148
160
|
|
|
149
161
|
return True
|
|
@@ -206,11 +218,14 @@ arguments:
|
|
|
206
218
|
|
|
207
219
|
# Display tool call information
|
|
208
220
|
PrettyOutput.section(f"Executing tool: {name}", OutputType.TOOL)
|
|
221
|
+
params = "Parameters:\n"
|
|
209
222
|
if isinstance(args, dict):
|
|
210
223
|
for key, value in args.items():
|
|
211
|
-
|
|
224
|
+
params += f"{key} = {value}\n"
|
|
212
225
|
else:
|
|
213
|
-
|
|
226
|
+
params += f"{args}"
|
|
227
|
+
|
|
228
|
+
PrettyOutput.print(params, OutputType.INFO)
|
|
214
229
|
|
|
215
230
|
# Execute tool call
|
|
216
231
|
result = self.execute_tool(name, args)
|
|
@@ -270,9 +285,10 @@ Please provide a summary:"""
|
|
|
270
285
|
|
|
271
286
|
else:
|
|
272
287
|
PrettyOutput.section("Execution failed", OutputType.WARNING)
|
|
288
|
+
PrettyOutput.print(result["stderr"], OutputType.WARNING)
|
|
273
289
|
|
|
274
290
|
if len(tool_calls) > 1:
|
|
275
|
-
output += f"\n\n---
|
|
291
|
+
output += f"\n\n--- Only one tool can be executed at a time, the following tools were not executed\n{str(tool_calls[1:])} ---"
|
|
276
292
|
return output
|
|
277
293
|
|
|
278
294
|
except Exception as e:
|
jarvis/tools/search.py
CHANGED
|
@@ -211,17 +211,19 @@ def main():
|
|
|
211
211
|
PrettyOutput.print(f"\nFound {len(results)} results:", OutputType.INFO)
|
|
212
212
|
|
|
213
213
|
for i, result in enumerate(results[:args.max], 1):
|
|
214
|
-
|
|
214
|
+
output = []
|
|
215
|
+
output.append(f"\n{'-'*50}")
|
|
215
216
|
if args.url_only:
|
|
216
|
-
|
|
217
|
+
output.append(f"{i}. {result['href']}")
|
|
217
218
|
else:
|
|
218
|
-
|
|
219
|
-
|
|
219
|
+
output.append(f"{i}. {result['title']}")
|
|
220
|
+
output.append(f"Link: {result['href']}")
|
|
220
221
|
if result['abstract']:
|
|
221
|
-
|
|
222
|
+
output.append(f"Abstract: {result['abstract']}")
|
|
223
|
+
PrettyOutput.print("\n".join(output), OutputType.INFO)
|
|
222
224
|
|
|
223
225
|
except KeyboardInterrupt:
|
|
224
|
-
PrettyOutput.print("
|
|
226
|
+
PrettyOutput.print("Search cancelled", OutputType.WARNING)
|
|
225
227
|
sys.exit(1)
|
|
226
228
|
except Exception as e:
|
|
227
229
|
PrettyOutput.print(f"Execution error: {str(e)}", OutputType.ERROR)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from typing import Dict, Any
|
|
1
|
+
from typing import Dict, Any
|
|
2
2
|
|
|
3
3
|
from jarvis.utils import OutputType, PrettyOutput
|
|
4
|
-
from jarvis.
|
|
4
|
+
from jarvis.jarvis_code_agent.file_select import select_files
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class CodeFileSelecterTool:
|
|
@@ -30,8 +30,8 @@ class CodeFileSelecterTool:
|
|
|
30
30
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
31
31
|
"""Execute interactive file selection"""
|
|
32
32
|
try:
|
|
33
|
-
related_files = args
|
|
34
|
-
root_dir = args.get("root_dir", ".")
|
|
33
|
+
related_files = args.get("related_files", [])
|
|
34
|
+
root_dir = args.get("root_dir", ".").strip()
|
|
35
35
|
|
|
36
36
|
PrettyOutput.print("Starting interactive file selection...", OutputType.INFO)
|
|
37
37
|
|