jarvis-ai-assistant 0.1.16__tar.gz → 0.1.18__tar.gz
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_ai_assistant-0.1.16/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.1.18}/PKG-INFO +137 -1
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/README.md +136 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/pyproject.toml +1 -1
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/setup.py +1 -1
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/__init__.py +1 -1
- jarvis_ai_assistant-0.1.18/src/jarvis/__pycache__/__init__.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/__pycache__/agent.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/__pycache__/main.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/agent.py +8 -6
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/main.py +6 -3
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/models/__pycache__/kimi.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/models/kimi.py +1 -3
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/tools/__init__.py +2 -0
- jarvis_ai_assistant-0.1.18/src/jarvis/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.18/src/jarvis/tools/__pycache__/base.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.18/src/jarvis/tools/__pycache__/calculator.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.18/src/jarvis/tools/__pycache__/calculator_tool.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.18/src/jarvis/tools/__pycache__/file_ops.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.18/src/jarvis/tools/__pycache__/generator.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.18/src/jarvis/tools/__pycache__/shell.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.18/src/jarvis/tools/base.py +195 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/tools/file_ops.py +22 -3
- jarvis_ai_assistant-0.1.18/src/jarvis/tools/generator.py +223 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/tools/shell.py +23 -6
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18/src/jarvis_ai_assistant.egg-info}/PKG-INFO +137 -1
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis_ai_assistant.egg-info/SOURCES.txt +4 -0
- jarvis_ai_assistant-0.1.16/src/jarvis/__pycache__/__init__.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.16/src/jarvis/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.16/src/jarvis/tools/__pycache__/base.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.16/src/jarvis/tools/__pycache__/file_ops.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.16/src/jarvis/tools/__pycache__/shell.cpython-313.pyc +0 -0
- jarvis_ai_assistant-0.1.16/src/jarvis/tools/base.py +0 -113
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/MANIFEST.in +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/setup.cfg +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/__pycache__/models.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/__pycache__/tools.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/__pycache__/utils.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/__pycache__/zte_llm.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/models/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/models/__pycache__/__init__.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/models/__pycache__/base.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/models/base.py +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/tools/__pycache__/bing_search.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/tools/__pycache__/python_script.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/tools/__pycache__/rag.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/tools/__pycache__/search.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/tools/__pycache__/sub_agent.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/tools/__pycache__/user_confirmation.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/tools/__pycache__/user_input.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/tools/__pycache__/user_interaction.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/tools/__pycache__/webpage.cpython-313.pyc +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis/utils.py +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis_ai_assistant.egg-info/dependency_links.txt +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis_ai_assistant.egg-info/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis_ai_assistant.egg-info/requires.txt +0 -0
- {jarvis_ai_assistant-0.1.16 → jarvis_ai_assistant-0.1.18}/src/jarvis_ai_assistant.egg-info/top_level.txt +0 -0
{jarvis_ai_assistant-0.1.16/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.1.18}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: jarvis-ai-assistant
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.18
|
|
4
4
|
Summary: Jarvis: An AI assistant that uses tools to interact with the system
|
|
5
5
|
Home-page: https://github.com/skyfireitdiy/Jarvis
|
|
6
6
|
Author: skyfire
|
|
@@ -87,6 +87,9 @@ Dynamic: requires-python
|
|
|
87
87
|
- File operations (read/write/append)
|
|
88
88
|
- Task automation
|
|
89
89
|
- Predefined task support
|
|
90
|
+
- Dynamic tool system with auto-loading
|
|
91
|
+
- AI-powered tool generation
|
|
92
|
+
- Custom tool development
|
|
90
93
|
|
|
91
94
|
🔄 **Interactive Experience**
|
|
92
95
|
- Natural language understanding
|
|
@@ -95,6 +98,139 @@ Dynamic: requires-python
|
|
|
95
98
|
- Multi-line input support
|
|
96
99
|
- Colored output with progress indicators
|
|
97
100
|
|
|
101
|
+
## 🛠️ Custom Tools
|
|
102
|
+
|
|
103
|
+
### Tool Locations
|
|
104
|
+
- Built-in tools: `src/jarvis/tools/`
|
|
105
|
+
- User tools: `~/.jarvis_tools/` (automatically created)
|
|
106
|
+
|
|
107
|
+
### Creating Tools
|
|
108
|
+
|
|
109
|
+
#### 1. Using AI Generator (Recommended)
|
|
110
|
+
```yaml
|
|
111
|
+
<START_TOOL_CALL>
|
|
112
|
+
name: generate_tool
|
|
113
|
+
arguments:
|
|
114
|
+
tool_name: calculator
|
|
115
|
+
class_name: CalculatorTool
|
|
116
|
+
description: Basic math calculations
|
|
117
|
+
parameters:
|
|
118
|
+
type: object
|
|
119
|
+
properties:
|
|
120
|
+
operation:
|
|
121
|
+
type: string
|
|
122
|
+
enum: ["add", "subtract", "multiply", "divide"]
|
|
123
|
+
numbers:
|
|
124
|
+
type: array
|
|
125
|
+
items:
|
|
126
|
+
type: number
|
|
127
|
+
required: ["operation", "numbers"]
|
|
128
|
+
<END_TOOL_CALL>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
#### 2. Manual Creation
|
|
132
|
+
Create a new Python file in `~/.jarvis_tools/`:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from typing import Dict, Any, Protocol, Optional
|
|
136
|
+
from enum import Enum
|
|
137
|
+
|
|
138
|
+
class OutputType(Enum):
|
|
139
|
+
INFO = "info"
|
|
140
|
+
ERROR = "error"
|
|
141
|
+
|
|
142
|
+
class OutputHandler(Protocol):
|
|
143
|
+
def print(self, text: str, output_type: OutputType) -> None: ...
|
|
144
|
+
|
|
145
|
+
class ModelHandler(Protocol):
|
|
146
|
+
def chat(self, message: str) -> str: ...
|
|
147
|
+
|
|
148
|
+
class CustomTool:
|
|
149
|
+
name = "tool_name" # Tool name for invocation
|
|
150
|
+
description = "Tool description" # Tool purpose
|
|
151
|
+
parameters = { # JSON Schema for parameters
|
|
152
|
+
"type": "object",
|
|
153
|
+
"properties": {
|
|
154
|
+
"param1": {"type": "string"}
|
|
155
|
+
},
|
|
156
|
+
"required": ["param1"]
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
def __init__(self, **kwargs):
|
|
160
|
+
"""Initialize tool with optional dependencies
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
model: AI model for advanced features
|
|
164
|
+
output_handler: For consistent output formatting
|
|
165
|
+
register: Access to tool registry
|
|
166
|
+
"""
|
|
167
|
+
self.model = kwargs.get('model')
|
|
168
|
+
self.output = kwargs.get('output_handler')
|
|
169
|
+
self.register = kwargs.get('register')
|
|
170
|
+
|
|
171
|
+
def _print(self, text: str, output_type: OutputType = OutputType.INFO):
|
|
172
|
+
"""Print formatted output"""
|
|
173
|
+
if self.output:
|
|
174
|
+
self.output.print(text, output_type)
|
|
175
|
+
|
|
176
|
+
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
177
|
+
"""Execute tool functionality
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
args: Parameters passed to the tool
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
Dict with execution results:
|
|
184
|
+
{
|
|
185
|
+
"success": bool,
|
|
186
|
+
"stdout": str, # On success
|
|
187
|
+
"stderr": str, # Optional error details
|
|
188
|
+
"error": str # On failure
|
|
189
|
+
}
|
|
190
|
+
"""
|
|
191
|
+
try:
|
|
192
|
+
# Implement tool logic here
|
|
193
|
+
result = "Tool execution result"
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
"success": True,
|
|
197
|
+
"stdout": result,
|
|
198
|
+
"stderr": ""
|
|
199
|
+
}
|
|
200
|
+
except Exception as e:
|
|
201
|
+
self._print(str(e), OutputType.ERROR)
|
|
202
|
+
return {
|
|
203
|
+
"success": False,
|
|
204
|
+
"error": str(e)
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Development Guidelines
|
|
209
|
+
|
|
210
|
+
1. **Tool Structure**
|
|
211
|
+
- Clear name and description
|
|
212
|
+
- Well-defined parameters schema
|
|
213
|
+
- Proper error handling
|
|
214
|
+
- Consistent output format
|
|
215
|
+
|
|
216
|
+
2. **Best Practices**
|
|
217
|
+
- Use `_print` for output
|
|
218
|
+
- Handle all required parameters
|
|
219
|
+
- Document functionality
|
|
220
|
+
- Return standardized results
|
|
221
|
+
- Keep tools focused and simple
|
|
222
|
+
|
|
223
|
+
3. **Testing**
|
|
224
|
+
- Verify parameter validation
|
|
225
|
+
- Test error handling
|
|
226
|
+
- Check output format
|
|
227
|
+
- Ensure proper cleanup
|
|
228
|
+
|
|
229
|
+
4. **Integration**
|
|
230
|
+
- Tools are auto-loaded on startup
|
|
231
|
+
- No manual registration needed
|
|
232
|
+
- Hot-reload supported
|
|
233
|
+
- Dependencies injected automatically
|
|
98
234
|
|
|
99
235
|
## ⚙️ Environment Setup
|
|
100
236
|
|
|
@@ -34,6 +34,9 @@
|
|
|
34
34
|
- File operations (read/write/append)
|
|
35
35
|
- Task automation
|
|
36
36
|
- Predefined task support
|
|
37
|
+
- Dynamic tool system with auto-loading
|
|
38
|
+
- AI-powered tool generation
|
|
39
|
+
- Custom tool development
|
|
37
40
|
|
|
38
41
|
🔄 **Interactive Experience**
|
|
39
42
|
- Natural language understanding
|
|
@@ -42,6 +45,139 @@
|
|
|
42
45
|
- Multi-line input support
|
|
43
46
|
- Colored output with progress indicators
|
|
44
47
|
|
|
48
|
+
## 🛠️ Custom Tools
|
|
49
|
+
|
|
50
|
+
### Tool Locations
|
|
51
|
+
- Built-in tools: `src/jarvis/tools/`
|
|
52
|
+
- User tools: `~/.jarvis_tools/` (automatically created)
|
|
53
|
+
|
|
54
|
+
### Creating Tools
|
|
55
|
+
|
|
56
|
+
#### 1. Using AI Generator (Recommended)
|
|
57
|
+
```yaml
|
|
58
|
+
<START_TOOL_CALL>
|
|
59
|
+
name: generate_tool
|
|
60
|
+
arguments:
|
|
61
|
+
tool_name: calculator
|
|
62
|
+
class_name: CalculatorTool
|
|
63
|
+
description: Basic math calculations
|
|
64
|
+
parameters:
|
|
65
|
+
type: object
|
|
66
|
+
properties:
|
|
67
|
+
operation:
|
|
68
|
+
type: string
|
|
69
|
+
enum: ["add", "subtract", "multiply", "divide"]
|
|
70
|
+
numbers:
|
|
71
|
+
type: array
|
|
72
|
+
items:
|
|
73
|
+
type: number
|
|
74
|
+
required: ["operation", "numbers"]
|
|
75
|
+
<END_TOOL_CALL>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### 2. Manual Creation
|
|
79
|
+
Create a new Python file in `~/.jarvis_tools/`:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from typing import Dict, Any, Protocol, Optional
|
|
83
|
+
from enum import Enum
|
|
84
|
+
|
|
85
|
+
class OutputType(Enum):
|
|
86
|
+
INFO = "info"
|
|
87
|
+
ERROR = "error"
|
|
88
|
+
|
|
89
|
+
class OutputHandler(Protocol):
|
|
90
|
+
def print(self, text: str, output_type: OutputType) -> None: ...
|
|
91
|
+
|
|
92
|
+
class ModelHandler(Protocol):
|
|
93
|
+
def chat(self, message: str) -> str: ...
|
|
94
|
+
|
|
95
|
+
class CustomTool:
|
|
96
|
+
name = "tool_name" # Tool name for invocation
|
|
97
|
+
description = "Tool description" # Tool purpose
|
|
98
|
+
parameters = { # JSON Schema for parameters
|
|
99
|
+
"type": "object",
|
|
100
|
+
"properties": {
|
|
101
|
+
"param1": {"type": "string"}
|
|
102
|
+
},
|
|
103
|
+
"required": ["param1"]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
def __init__(self, **kwargs):
|
|
107
|
+
"""Initialize tool with optional dependencies
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
model: AI model for advanced features
|
|
111
|
+
output_handler: For consistent output formatting
|
|
112
|
+
register: Access to tool registry
|
|
113
|
+
"""
|
|
114
|
+
self.model = kwargs.get('model')
|
|
115
|
+
self.output = kwargs.get('output_handler')
|
|
116
|
+
self.register = kwargs.get('register')
|
|
117
|
+
|
|
118
|
+
def _print(self, text: str, output_type: OutputType = OutputType.INFO):
|
|
119
|
+
"""Print formatted output"""
|
|
120
|
+
if self.output:
|
|
121
|
+
self.output.print(text, output_type)
|
|
122
|
+
|
|
123
|
+
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
124
|
+
"""Execute tool functionality
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
args: Parameters passed to the tool
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
Dict with execution results:
|
|
131
|
+
{
|
|
132
|
+
"success": bool,
|
|
133
|
+
"stdout": str, # On success
|
|
134
|
+
"stderr": str, # Optional error details
|
|
135
|
+
"error": str # On failure
|
|
136
|
+
}
|
|
137
|
+
"""
|
|
138
|
+
try:
|
|
139
|
+
# Implement tool logic here
|
|
140
|
+
result = "Tool execution result"
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
"success": True,
|
|
144
|
+
"stdout": result,
|
|
145
|
+
"stderr": ""
|
|
146
|
+
}
|
|
147
|
+
except Exception as e:
|
|
148
|
+
self._print(str(e), OutputType.ERROR)
|
|
149
|
+
return {
|
|
150
|
+
"success": False,
|
|
151
|
+
"error": str(e)
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Development Guidelines
|
|
156
|
+
|
|
157
|
+
1. **Tool Structure**
|
|
158
|
+
- Clear name and description
|
|
159
|
+
- Well-defined parameters schema
|
|
160
|
+
- Proper error handling
|
|
161
|
+
- Consistent output format
|
|
162
|
+
|
|
163
|
+
2. **Best Practices**
|
|
164
|
+
- Use `_print` for output
|
|
165
|
+
- Handle all required parameters
|
|
166
|
+
- Document functionality
|
|
167
|
+
- Return standardized results
|
|
168
|
+
- Keep tools focused and simple
|
|
169
|
+
|
|
170
|
+
3. **Testing**
|
|
171
|
+
- Verify parameter validation
|
|
172
|
+
- Test error handling
|
|
173
|
+
- Check output format
|
|
174
|
+
- Ensure proper cleanup
|
|
175
|
+
|
|
176
|
+
4. **Integration**
|
|
177
|
+
- Tools are auto-loaded on startup
|
|
178
|
+
- No manual registration needed
|
|
179
|
+
- Hot-reload supported
|
|
180
|
+
- Dependencies injected automatically
|
|
45
181
|
|
|
46
182
|
## ⚙️ Environment Setup
|
|
47
183
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "jarvis-ai-assistant"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.18"
|
|
8
8
|
description = "Jarvis: An AI assistant that uses tools to interact with the system"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "Your Name", email = "your.email@example.com" }]
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name="jarvis-ai-assistant",
|
|
5
|
-
version="0.1.
|
|
5
|
+
version="0.1.18",
|
|
6
6
|
author="skyfire",
|
|
7
7
|
author_email="skyfireitdiy@hotmail.com",
|
|
8
8
|
description="An AI assistant that uses various tools to interact with the system",
|
|
Binary file
|
|
Binary file
|
|
@@ -77,12 +77,13 @@ class Agent:
|
|
|
77
77
|
except Exception as e:
|
|
78
78
|
raise Exception(f"{self.name}: 模型调用失败: {str(e)}")
|
|
79
79
|
|
|
80
|
-
def run(self, user_input: str, file_list: Optional[List[str]] = None):
|
|
80
|
+
def run(self, user_input: str, file_list: Optional[List[str]] = None, keep_history: bool = False):
|
|
81
81
|
"""处理用户输入并返回响应,返回任务总结报告
|
|
82
82
|
|
|
83
83
|
Args:
|
|
84
84
|
user_input: 用户输入的任务描述
|
|
85
85
|
file_list: 可选的文件列表,默认为None
|
|
86
|
+
keep_history: 是否保留对话历史,默认为False
|
|
86
87
|
|
|
87
88
|
Returns:
|
|
88
89
|
str: 任务总结报告
|
|
@@ -245,11 +246,12 @@ arguments:
|
|
|
245
246
|
return f"Task failed: {str(e)}"
|
|
246
247
|
|
|
247
248
|
finally:
|
|
248
|
-
#
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
249
|
+
# 只在不保留历史时删除会话
|
|
250
|
+
if not keep_history:
|
|
251
|
+
try:
|
|
252
|
+
self.model.delete_chat()
|
|
253
|
+
except Exception as e:
|
|
254
|
+
PrettyOutput.print(f"清理会话时发生错误: {str(e)}", OutputType.ERROR)
|
|
253
255
|
|
|
254
256
|
def clear_history(self):
|
|
255
257
|
"""清除对话历史,只保留系统提示"""
|
|
@@ -90,6 +90,7 @@ def main():
|
|
|
90
90
|
# Add argument parser
|
|
91
91
|
parser = argparse.ArgumentParser(description='Jarvis AI Assistant')
|
|
92
92
|
parser.add_argument('-f', '--files', nargs='*', help='List of files to process')
|
|
93
|
+
parser.add_argument('--keep-history', action='store_true', help='Keep chat history (do not delete chat session)')
|
|
93
94
|
args = parser.parse_args()
|
|
94
95
|
|
|
95
96
|
load_env_from_file()
|
|
@@ -120,11 +121,13 @@ def main():
|
|
|
120
121
|
|
|
121
122
|
model = KimiModel(kimi_api_key)
|
|
122
123
|
|
|
123
|
-
tool_registry = ToolRegistry(
|
|
124
|
+
tool_registry = ToolRegistry()
|
|
124
125
|
agent = Agent(model, tool_registry)
|
|
125
126
|
|
|
126
127
|
# 欢迎信息
|
|
127
128
|
PrettyOutput.print(f"Jarvis 已初始化 - With Kimi", OutputType.SYSTEM)
|
|
129
|
+
if args.keep_history:
|
|
130
|
+
PrettyOutput.print("已启用历史保留模式", OutputType.INFO)
|
|
128
131
|
|
|
129
132
|
# 加载预定义任务
|
|
130
133
|
tasks = load_tasks()
|
|
@@ -132,7 +135,7 @@ def main():
|
|
|
132
135
|
selected_task = select_task(tasks)
|
|
133
136
|
if selected_task:
|
|
134
137
|
PrettyOutput.print(f"\n执行任务: {selected_task}", OutputType.INFO)
|
|
135
|
-
agent.run(selected_task, args.files)
|
|
138
|
+
agent.run(selected_task, args.files, keep_history=args.keep_history)
|
|
136
139
|
return 0
|
|
137
140
|
|
|
138
141
|
# 如果没有选择预定义任务,进入交互模式
|
|
@@ -141,7 +144,7 @@ def main():
|
|
|
141
144
|
user_input = get_multiline_input("请输入您的任务(输入空行退出):")
|
|
142
145
|
if not user_input or user_input == "__interrupt__":
|
|
143
146
|
break
|
|
144
|
-
agent.run(user_input, args.files)
|
|
147
|
+
agent.run(user_input, args.files, keep_history=args.keep_history)
|
|
145
148
|
except Exception as e:
|
|
146
149
|
PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
|
|
147
150
|
|
|
Binary file
|
|
@@ -261,7 +261,7 @@ class KimiModel(BaseModel):
|
|
|
261
261
|
response = requests.delete(url, headers=headers)
|
|
262
262
|
if response.status_code == 200:
|
|
263
263
|
PrettyOutput.print("会话已删除", OutputType.SUCCESS)
|
|
264
|
-
self.
|
|
264
|
+
self.reset()
|
|
265
265
|
return True
|
|
266
266
|
else:
|
|
267
267
|
PrettyOutput.print(f"删除会话失败: HTTP {response.status_code}", OutputType.ERROR)
|
|
@@ -272,8 +272,6 @@ class KimiModel(BaseModel):
|
|
|
272
272
|
|
|
273
273
|
def reset(self):
|
|
274
274
|
"""重置对话"""
|
|
275
|
-
if self.chat_id:
|
|
276
|
-
self.delete_chat() # 删除现有会话
|
|
277
275
|
self.chat_id = ""
|
|
278
276
|
self.uploaded_files = []
|
|
279
277
|
self.first_chat = True # 重置first_chat标记
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
from .base import Tool, ToolRegistry
|
|
2
2
|
from .file_ops import FileOperationTool
|
|
3
3
|
from .shell import ShellTool
|
|
4
|
+
from .generator import ToolGeneratorTool
|
|
4
5
|
|
|
5
6
|
__all__ = [
|
|
6
7
|
'Tool',
|
|
7
8
|
'ToolRegistry',
|
|
8
9
|
'FileOperationTool',
|
|
9
10
|
'ShellTool',
|
|
11
|
+
'ToolGeneratorTool',
|
|
10
12
|
]
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
from typing import Dict, Any, List, Optional, Callable, Type
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import importlib.util
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
from jarvis.models.kimi import KimiModel
|
|
9
|
+
|
|
10
|
+
from ..utils import PrettyOutput, OutputType
|
|
11
|
+
from ..models import BaseModel
|
|
12
|
+
|
|
13
|
+
class Tool:
|
|
14
|
+
def __init__(self, name: str, description: str, parameters: Dict, func: Callable):
|
|
15
|
+
self.name = name
|
|
16
|
+
self.description = description
|
|
17
|
+
self.parameters = parameters
|
|
18
|
+
self.func = func
|
|
19
|
+
|
|
20
|
+
def to_dict(self) -> Dict:
|
|
21
|
+
"""转换为工具格式"""
|
|
22
|
+
return {
|
|
23
|
+
"name": self.name,
|
|
24
|
+
"description": self.description,
|
|
25
|
+
"parameters": json.dumps(self.parameters)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
def execute(self, arguments: Dict) -> Dict[str, Any]:
|
|
29
|
+
"""执行工具函数"""
|
|
30
|
+
return self.func(arguments)
|
|
31
|
+
|
|
32
|
+
class ToolRegistry:
|
|
33
|
+
def __init__(self, output_handler=None):
|
|
34
|
+
"""初始化工具注册器
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
output_handler: 输出处理器 (可选)
|
|
38
|
+
"""
|
|
39
|
+
self.tools: Dict[str, Tool] = {}
|
|
40
|
+
self.output_handler = output_handler or PrettyOutput
|
|
41
|
+
|
|
42
|
+
# 加载内置工具和外部工具
|
|
43
|
+
self._load_builtin_tools()
|
|
44
|
+
self._load_external_tools()
|
|
45
|
+
|
|
46
|
+
def _load_builtin_tools(self):
|
|
47
|
+
"""从内置tools目录加载工具"""
|
|
48
|
+
tools_dir = Path(__file__).parent
|
|
49
|
+
|
|
50
|
+
# 遍历目录下的所有.py文件
|
|
51
|
+
for file_path in tools_dir.glob("*.py"):
|
|
52
|
+
# 跳过基础文件和__init__.py
|
|
53
|
+
if file_path.name in ["base.py", "__init__.py"]:
|
|
54
|
+
continue
|
|
55
|
+
|
|
56
|
+
self.register_tool_by_file(file_path)
|
|
57
|
+
|
|
58
|
+
def _load_external_tools(self):
|
|
59
|
+
"""从~/.jarvis_tools加载外部工具"""
|
|
60
|
+
external_tools_dir = Path.home() / '.jarvis_tools'
|
|
61
|
+
if not external_tools_dir.exists():
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
# 遍历目录下的所有.py文件
|
|
65
|
+
for file_path in external_tools_dir.glob("*.py"):
|
|
66
|
+
# 跳过__init__.py
|
|
67
|
+
if file_path.name == "__init__.py":
|
|
68
|
+
continue
|
|
69
|
+
|
|
70
|
+
self.register_tool_by_file(file_path)
|
|
71
|
+
|
|
72
|
+
def register_tool_by_file(self, file_path: str):
|
|
73
|
+
"""从指定文件加载并注册工具
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
file_path: 工具文件的路径
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
bool: 是否成功加载工具
|
|
80
|
+
"""
|
|
81
|
+
try:
|
|
82
|
+
file_path = Path(file_path).resolve() # 获取绝对路径
|
|
83
|
+
if not file_path.exists() or not file_path.is_file():
|
|
84
|
+
self.output_handler.print(f"文件不存在: {file_path}", OutputType.ERROR)
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
# 动态导入模块
|
|
88
|
+
module_name = file_path.stem
|
|
89
|
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
|
90
|
+
if not spec or not spec.loader:
|
|
91
|
+
self.output_handler.print(f"无法加载模块: {file_path}", OutputType.ERROR)
|
|
92
|
+
return False
|
|
93
|
+
|
|
94
|
+
module = importlib.util.module_from_spec(spec)
|
|
95
|
+
sys.modules[module_name] = module # 添加到 sys.modules 以支持相对导入
|
|
96
|
+
spec.loader.exec_module(module)
|
|
97
|
+
|
|
98
|
+
# 查找模块中的工具类
|
|
99
|
+
tool_found = False
|
|
100
|
+
for item_name in dir(module):
|
|
101
|
+
item = getattr(module, item_name)
|
|
102
|
+
# 检查是否是类,并且有必要的属性
|
|
103
|
+
if (isinstance(item, type) and
|
|
104
|
+
hasattr(item, 'name') and
|
|
105
|
+
hasattr(item, 'description') and
|
|
106
|
+
hasattr(item, 'parameters')):
|
|
107
|
+
|
|
108
|
+
# 实例化工具类,传入模型和输出处理器
|
|
109
|
+
tool_instance = item(model=KimiModel(), register=self, output_handler=self.output_handler)
|
|
110
|
+
|
|
111
|
+
# 注册工具
|
|
112
|
+
self.register_tool(
|
|
113
|
+
name=tool_instance.name,
|
|
114
|
+
description=tool_instance.description,
|
|
115
|
+
parameters=tool_instance.parameters,
|
|
116
|
+
func=tool_instance.execute
|
|
117
|
+
)
|
|
118
|
+
self.output_handler.print(f"已加载工具: {tool_instance.name}", OutputType.INFO)
|
|
119
|
+
tool_found = True
|
|
120
|
+
|
|
121
|
+
if not tool_found:
|
|
122
|
+
self.output_handler.print(f"文件中未找到有效的工具类: {file_path}", OutputType.WARNING)
|
|
123
|
+
return False
|
|
124
|
+
|
|
125
|
+
return True
|
|
126
|
+
|
|
127
|
+
except Exception as e:
|
|
128
|
+
self.output_handler.print(f"加载工具失败 {file_path.name}: {str(e)}", OutputType.ERROR)
|
|
129
|
+
return False
|
|
130
|
+
|
|
131
|
+
def register_tool(self, name: str, description: str, parameters: Dict, func: Callable):
|
|
132
|
+
"""注册新工具"""
|
|
133
|
+
self.tools[name] = Tool(name, description, parameters, func)
|
|
134
|
+
|
|
135
|
+
def get_tool(self, name: str) -> Optional[Tool]:
|
|
136
|
+
"""获取工具"""
|
|
137
|
+
return self.tools.get(name)
|
|
138
|
+
|
|
139
|
+
def get_all_tools(self) -> List[Dict]:
|
|
140
|
+
"""获取所有工具的Ollama格式定义"""
|
|
141
|
+
return [tool.to_dict() for tool in self.tools.values()]
|
|
142
|
+
|
|
143
|
+
def execute_tool(self, name: str, arguments: Dict) -> Dict[str, Any]:
|
|
144
|
+
"""执行指定工具"""
|
|
145
|
+
tool = self.get_tool(name)
|
|
146
|
+
if tool is None:
|
|
147
|
+
return {"success": False, "error": f"Tool {name} does not exist"}
|
|
148
|
+
return tool.execute(arguments)
|
|
149
|
+
|
|
150
|
+
def handle_tool_calls(self, tool_calls: List[Dict]) -> str:
|
|
151
|
+
"""处理工具调用,只处理第一个工具"""
|
|
152
|
+
if not tool_calls:
|
|
153
|
+
return ""
|
|
154
|
+
|
|
155
|
+
# 只处理第一个工具调用
|
|
156
|
+
tool_call = tool_calls[0]
|
|
157
|
+
name = tool_call["name"]
|
|
158
|
+
args = tool_call["arguments"]
|
|
159
|
+
|
|
160
|
+
if isinstance(args, str):
|
|
161
|
+
try:
|
|
162
|
+
args = json.loads(args)
|
|
163
|
+
except json.JSONDecodeError:
|
|
164
|
+
PrettyOutput.print(f"工具参数格式无效: {name}", OutputType.ERROR)
|
|
165
|
+
return ""
|
|
166
|
+
|
|
167
|
+
# 显示工具调用信息
|
|
168
|
+
PrettyOutput.section(f"执行工具: {name}", OutputType.TOOL)
|
|
169
|
+
if isinstance(args, dict):
|
|
170
|
+
for key, value in args.items():
|
|
171
|
+
PrettyOutput.print(f"参数: {key} = {value}", OutputType.DEBUG)
|
|
172
|
+
else:
|
|
173
|
+
PrettyOutput.print(f"参数: {args}", OutputType.DEBUG)
|
|
174
|
+
|
|
175
|
+
# 执行工具调用
|
|
176
|
+
result = self.execute_tool(name, args)
|
|
177
|
+
|
|
178
|
+
# 处理结果
|
|
179
|
+
if result["success"]:
|
|
180
|
+
stdout = result["stdout"]
|
|
181
|
+
stderr = result.get("stderr", "")
|
|
182
|
+
output_parts = []
|
|
183
|
+
if stdout:
|
|
184
|
+
output_parts.append(f"输出:\n{stdout}")
|
|
185
|
+
if stderr:
|
|
186
|
+
output_parts.append(f"错误:\n{stderr}")
|
|
187
|
+
output = "\n\n".join(output_parts)
|
|
188
|
+
output = "没有输出和错误" if not output else output
|
|
189
|
+
PrettyOutput.section("执行成功", OutputType.SUCCESS)
|
|
190
|
+
else:
|
|
191
|
+
error_msg = result["error"]
|
|
192
|
+
output = f"执行失败: {error_msg}"
|
|
193
|
+
PrettyOutput.section("执行失败", OutputType.ERROR)
|
|
194
|
+
|
|
195
|
+
return output
|