jarvis-ai-assistant 0.1.179__py3-none-any.whl → 0.1.180__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 CHANGED
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Jarvis AI Assistant"""
3
3
 
4
- __version__ = "0.1.179"
4
+ __version__ = "0.1.180"
@@ -0,0 +1,260 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "Jarvis环境变量配置模式",
4
+ "description": "Jarvis系统配置模式",
5
+ "type": "object",
6
+ "properties": {
7
+ "JARVIS_MCP": {
8
+ "type": "array",
9
+ "description": "MCP工具配置列表",
10
+ "items": {
11
+ "type": "object",
12
+ "oneOf": [
13
+ {
14
+ "type": "object",
15
+ "required": [
16
+ "type",
17
+ "base_url"
18
+ ],
19
+ "properties": {
20
+ "type": {
21
+ "type": "string",
22
+ "enum": [
23
+ "sse",
24
+ "streamable"
25
+ ],
26
+ "description": "MCP客户端类型"
27
+ },
28
+ "base_url": {
29
+ "type": "string",
30
+ "format": "uri",
31
+ "description": "MCP服务器基础URL"
32
+ },
33
+ "auth_token": {
34
+ "type": "string",
35
+ "description": "认证令牌(可选)"
36
+ },
37
+ "headers": {
38
+ "type": "object",
39
+ "additionalProperties": {
40
+ "type": "string"
41
+ },
42
+ "description": "额外的HTTP头(可选)"
43
+ },
44
+ "name": {
45
+ "type": "string",
46
+ "description": "工具名称(可选)"
47
+ },
48
+ "enable": {
49
+ "type": "boolean",
50
+ "default": true,
51
+ "description": "是否启用该工具(可选)"
52
+ }
53
+ }
54
+ },
55
+ {
56
+ "type": "object",
57
+ "required": [
58
+ "type",
59
+ "command"
60
+ ],
61
+ "properties": {
62
+ "type": {
63
+ "type": "string",
64
+ "enum": [
65
+ "stdio"
66
+ ],
67
+ "description": "MCP客户端类型"
68
+ },
69
+ "command": {
70
+ "type": "string",
71
+ "description": "要执行的命令"
72
+ },
73
+ "args": {
74
+ "type": "array",
75
+ "items": {
76
+ "type": "string"
77
+ },
78
+ "description": "命令参数列表(可选)"
79
+ },
80
+ "env": {
81
+ "type": "object",
82
+ "additionalProperties": {
83
+ "type": "string"
84
+ },
85
+ "description": "环境变量(可选)"
86
+ },
87
+ "name": {
88
+ "type": "string",
89
+ "description": "工具名称(可选)"
90
+ },
91
+ "enable": {
92
+ "type": "boolean",
93
+ "default": true,
94
+ "description": "是否启用该工具(可选)"
95
+ }
96
+ }
97
+ }
98
+ ]
99
+ }
100
+ },
101
+ "ENV": {
102
+ "type": "object",
103
+ "description": "需要设置的额外环境变量",
104
+ "additionalProperties": {
105
+ "type": "string"
106
+ },
107
+ "default": {}
108
+ },
109
+ "JARVIS_GIT_COMMIT_PROMPT": {
110
+ "type": "string",
111
+ "description": "Git提交信息生成提示模板",
112
+ "default": ""
113
+ },
114
+ "JARVIS_MAX_TOKEN_COUNT": {
115
+ "type": "string",
116
+ "description": "模型能处理的最大token数量",
117
+ "default": "960000"
118
+ },
119
+ "JARVIS_MAX_INPUT_TOKEN_COUNT": {
120
+ "type": "string",
121
+ "description": "模型能处理的最大输入token数量",
122
+ "default": "32000"
123
+ },
124
+ "JARVIS_AUTO_COMPLETE": {
125
+ "type": "string",
126
+ "description": "是否启用自动补全功能",
127
+ "default": "false",
128
+ "enum": [
129
+ "true",
130
+ "false"
131
+ ]
132
+ },
133
+ "SHELL": {
134
+ "type": "string",
135
+ "description": "系统shell名称(如: bash, zsh)",
136
+ "default": "/bin/bash"
137
+ },
138
+ "JARVIS_PLATFORM": {
139
+ "type": "string",
140
+ "description": "常规操作平台名称",
141
+ "default": "yuanbao"
142
+ },
143
+ "JARVIS_MODEL": {
144
+ "type": "string",
145
+ "description": "常规操作模型名称",
146
+ "default": "deep_seek_v3"
147
+ },
148
+ "JARVIS_THINKING_PLATFORM": {
149
+ "type": "string",
150
+ "description": "思考操作平台名称",
151
+ "default": "yuanbao"
152
+ },
153
+ "JARVIS_THINKING_MODEL": {
154
+ "type": "string",
155
+ "description": "思考操作模型名称",
156
+ "default": "deep_seek"
157
+ },
158
+ "JARVIS_EXECUTE_TOOL_CONFIRM": {
159
+ "type": "string",
160
+ "description": "执行工具前是否需要确认",
161
+ "default": "false",
162
+ "enum": [
163
+ "true",
164
+ "false"
165
+ ]
166
+ },
167
+ "JARVIS_CONFIRM_BEFORE_APPLY_PATCH": {
168
+ "type": "string",
169
+ "description": "应用补丁前是否需要确认",
170
+ "default": "true",
171
+ "enum": [
172
+ "true",
173
+ "false"
174
+ ]
175
+ },
176
+ "JARVIS_MAX_TOOL_CALL_COUNT": {
177
+ "type": "string",
178
+ "description": "最大连续工具调用次数",
179
+ "default": "20"
180
+ },
181
+ "JARVIS_DATA_PATH": {
182
+ "type": "string",
183
+ "description": "Jarvis数据存储目录路径",
184
+ "default": "~/.jarvis"
185
+ },
186
+ "JARVIS_AUTO_UPDATE": {
187
+ "type": "string",
188
+ "description": "是否自动更新git仓库",
189
+ "default": "true",
190
+ "enum": [
191
+ "true",
192
+ "false"
193
+ ]
194
+ },
195
+ "JARVIS_MAX_BIG_CONTENT_SIZE": {
196
+ "type": "string",
197
+ "description": "最大大内容尺寸",
198
+ "default": "1024000"
199
+ },
200
+ "JARVIS_PRETTY_OUTPUT": {
201
+ "type": "string",
202
+ "description": "是否启用美化输出",
203
+ "default": "false",
204
+ "enum": [
205
+ "true",
206
+ "false"
207
+ ]
208
+ },
209
+ "JARVIS_USE_METHODOLOGY": {
210
+ "type": "string",
211
+ "description": "是否启用方法论",
212
+ "default": "false",
213
+ "enum": [
214
+ "true",
215
+ "false"
216
+ ]
217
+ },
218
+ "JARVIS_USE_ANALYSIS": {
219
+ "type": "string",
220
+ "description": "是否启用任务分析",
221
+ "default": "false",
222
+ "enum": [
223
+ "true",
224
+ "false"
225
+ ]
226
+ },
227
+ "JARVIS_PRINT_PROMPT": {
228
+ "type": "string",
229
+ "description": "是否打印提示",
230
+ "default": "false",
231
+ "enum": [
232
+ "true",
233
+ "false"
234
+ ]
235
+ },
236
+ "JARVIS_REPLACE_MAP": {
237
+ "type": "object",
238
+ "description": "自定义替换映射表配置",
239
+ "additionalProperties": {
240
+ "type": "object",
241
+ "properties": {
242
+ "append": {
243
+ "type": "boolean",
244
+ "description": "Whether to append to existing template"
245
+ },
246
+ "template": {
247
+ "type": "string",
248
+ "description": "Replacement template content"
249
+ },
250
+ "description": {
251
+ "type": "string",
252
+ "description": "Description of the replacement"
253
+ }
254
+ },
255
+ "required": ["template"]
256
+ }
257
+ }
258
+ },
259
+ "additionalProperties": false
260
+ }
@@ -252,7 +252,7 @@ class GitCommitTool:
252
252
  "stdout": yaml.safe_dump({
253
253
  "commit_hash": commit_hash,
254
254
  "commit_message": commit_message
255
- }),
255
+ }, allow_unicode=True),
256
256
  "stderr": ""
257
257
  }
258
258
  finally:
@@ -6,10 +6,6 @@ import time
6
6
  from typing import Dict, Generator, List, Tuple
7
7
 
8
8
  import requests # type: ignore
9
- from rich import box
10
- from rich.live import Live
11
- from rich.panel import Panel
12
- from rich.text import Text
13
9
 
14
10
  from jarvis.jarvis_platform.base import BasePlatform
15
11
  from jarvis.jarvis_utils.config import get_data_dir
@@ -37,24 +33,6 @@ class KimiModel(BasePlatform):
37
33
  self.chat_id = ""
38
34
  self.api_key = os.getenv("KIMI_API_KEY")
39
35
  if not self.api_key:
40
- message = (
41
- "需要设置 KIMI_API_KEY 才能使用 Jarvis。请按照以下步骤操作:\n"
42
- "1. 获取 Kimi API Key:\n"
43
- " • 访问 Kimi AI 平台: https://kimi.moonshot.cn\n"
44
- " • 登录您的账户\n"
45
- " • 打开浏览器开发者工具 (F12 或右键 -> 检查)\n"
46
- " • 切换到网络标签\n"
47
- " • 发送任意消息\n"
48
- " • 在请求中找到 Authorization 头\n"
49
- " • 复制 token 值(去掉 'Bearer ' 前缀)\n"
50
- "2. 设置环境变量:\n"
51
- " • 方法 1: 创建或编辑配置文件:\n"
52
- f" echo 'KIMI_API_KEY=your_key_here' > {get_data_dir()}/env\n"
53
- " • 方法 2: 直接设置环境变量:\n"
54
- " export KIMI_API_KEY=your_key_here\n"
55
- "设置后,重新运行 Jarvis。"
56
- )
57
- PrettyOutput.print(message, OutputType.INFO)
58
36
  PrettyOutput.print("KIMI_API_KEY 未设置", OutputType.WARNING)
59
37
  self.auth_header = f"Bearer {self.api_key}"
60
38
  self.uploaded_files = [] # 存储已上传文件的信息
@@ -19,21 +19,6 @@ class OpenAIModel(BasePlatform):
19
19
  self.system_message = ""
20
20
  self.api_key = os.getenv("OPENAI_API_KEY")
21
21
  if not self.api_key:
22
- message = (
23
- "需要设置以下环境变量才能使用 OpenAI 模型:\n"
24
- " • OPENAI_API_KEY: API 密钥\n"
25
- " • OPENAI_API_BASE: (可选) API 基础地址, 默认使用 https://api.openai.com/v1\n"
26
- "您可以通过以下方式设置它们:\n"
27
- "1. 创建或编辑 ~/.jarvis/env 文件:\n"
28
- " OPENAI_API_KEY=your_api_key\n"
29
- " OPENAI_API_BASE=your_api_base\n"
30
- " OPENAI_MODEL_NAME=your_model_name\n"
31
- "2. 直接设置环境变量:\n"
32
- " export OPENAI_API_KEY=your_api_key\n"
33
- " export OPENAI_API_BASE=your_api_base\n"
34
- " export OPENAI_MODEL_NAME=your_model_name"
35
- )
36
- PrettyOutput.print(message, OutputType.INFO)
37
22
  PrettyOutput.print("OPENAI_API_KEY 未设置", OutputType.WARNING)
38
23
 
39
24
  self.base_url = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
@@ -9,10 +9,6 @@ from typing import Dict, Generator, List, Tuple
9
9
 
10
10
  import requests
11
11
  from PIL import Image
12
- from rich import box
13
- from rich.live import Live
14
- from rich.panel import Panel
15
- from rich.text import Text
16
12
  from yaspin import yaspin
17
13
  from yaspin.api import Yaspin
18
14
  from yaspin.spinners import Spinners
@@ -43,25 +39,6 @@ class YuanbaoPlatform(BasePlatform):
43
39
  self.agent_id = os.getenv("YUANBAO_AGENT_ID") # 代理ID
44
40
 
45
41
  if not self.cookies:
46
- message = (
47
- "需要设置 YUANBAO_COOKIES 和 YUANBAO_AGENT_ID 才能使用 Jarvis 的元宝功能。请按照以下步骤操作:\n"
48
- "1. 获取元宝 API 参数:\n"
49
- " • 访问元宝平台: https://yuanbao.tencent.com\n"
50
- " • 登录您的账户\n"
51
- " • 打开浏览器开发者工具 (F12 或右键 -> 检查)\n"
52
- " • 切换到网络标签\n"
53
- " • 发送任意消息\n"
54
- " • 查看请求中的 Cookie 和 AgentID 值(具体位置见README.md中截图)\n"
55
- "2. 设置环境变量:\n"
56
- " • 方法 1: 创建或编辑配置文件:\n"
57
- f" echo 'YUANBAO_COOKIES=your_cookies_here' >> {get_data_dir()}/env\n"
58
- f" echo 'YUANBAO_AGENT_ID=your_agent_id_here' >> {get_data_dir()}/env\n"
59
- " • 方法 2: 直接设置环境变量:\n"
60
- " export YUANBAO_COOKIES=your_cookies_here\n"
61
- " export YUANBAO_AGENT_ID=your_agent_id_here\n"
62
- "设置后,重新运行 Jarvis。"
63
- )
64
- PrettyOutput.print(message, OutputType.INFO)
65
42
  PrettyOutput.print("YUANBAO_COOKIES 未设置", OutputType.WARNING)
66
43
 
67
44
  self.system_message = "" # 系统消息,用于初始化对话
@@ -8,7 +8,7 @@ from typing import Optional
8
8
  from sympy import false
9
9
 
10
10
  from jarvis.jarvis_platform.registry import PlatformRegistry
11
- from jarvis.jarvis_utils.config import get_shell_name
11
+ from jarvis.jarvis_utils.config import get_shell_name, set_config
12
12
  from jarvis.jarvis_utils.input import get_multiline_input
13
13
  from jarvis.jarvis_utils.utils import init_env
14
14
 
@@ -90,7 +90,7 @@ def process_request(request: str) -> Optional[str]:
90
90
 
91
91
  # 规则
92
92
  1. 只输出命令
93
- 2. 不要解释或标记
93
+ 2. 不要输出任何命令之外的内容
94
94
  3. 单行输出
95
95
  4. 多个命令用&&连接
96
96
 
@@ -116,8 +116,11 @@ def process_request(request: str) -> Optional[str]:
116
116
  return None
117
117
 
118
118
  def main() -> int:
119
- # 创建参数解析器s
119
+ # 创建参数解析器
120
120
  init_env("")
121
+
122
+ set_config("JARVIS_PRINT_PROMPT", "false")
123
+
121
124
  parser = argparse.ArgumentParser(
122
125
  description="将自然语言要求转换为shell命令",
123
126
  formatter_class=argparse.RawDescriptionHelpFormatter,
@@ -156,7 +156,7 @@ class FileSearchReplaceTool:
156
156
  with yaspin(text=f"正在处理文件 {file_path}...", color="cyan") as spinner:
157
157
  success, temp_content = fast_edit(file_path, changes, spinner)
158
158
  if not success:
159
- success, temp_content = slow_edit(file_path, yaml.safe_dump(changes), spinner)
159
+ success, temp_content = slow_edit(file_path, yaml.safe_dump(changes, allow_unicode=True), spinner)
160
160
 
161
161
  # 只有当所有替换操作都成功时,才写回文件
162
162
  if success and (temp_content != original_content or not file_exists):
@@ -198,7 +198,7 @@ class ToolRegistry(OutputHandlerProtocol):
198
198
  stats_file = Path(get_data_dir()) / "tool_stat.yaml"
199
199
  try:
200
200
  with open(stats_file, "w", encoding="utf-8") as f:
201
- yaml.safe_dump(stats, f)
201
+ yaml.safe_dump(stats, f, allow_unicode=True)
202
202
  except Exception as e:
203
203
  PrettyOutput.print(
204
204
  f"保存工具调用统计失败: {str(e)}", OutputType.WARNING
@@ -229,14 +229,36 @@ class ToolRegistry(OutputHandlerProtocol):
229
229
  }
230
230
 
231
231
  def _load_mcp_tools(self) -> None:
232
- """从jarvis_data/tools/mcp加载工具"""
232
+ """加载MCP工具,优先从配置获取,其次从目录扫描"""
233
+ from jarvis.jarvis_utils.config import get_mcp_config
234
+
235
+ # 优先从配置获取MCP工具配置
236
+ mcp_configs = get_mcp_config()
237
+ if mcp_configs:
238
+ for config in mcp_configs:
239
+ self.register_mcp_tool_by_config(config)
240
+ return
241
+
242
+ # 如果配置中没有,则扫描目录
233
243
  mcp_tools_dir = Path(get_data_dir()) / "mcp"
234
244
  if not mcp_tools_dir.exists():
235
245
  return
236
246
 
247
+ # 添加警告信息
248
+ PrettyOutput.print(
249
+ "警告: 从文件目录加载MCP工具的方式将在未来版本中废弃,请尽快迁移到JARVIS_MCP配置方式",
250
+ OutputType.WARNING
251
+ )
252
+
237
253
  # 遍历目录中的所有.yaml文件
238
254
  for file_path in mcp_tools_dir.glob("*.yaml"):
239
- self.register_mcp_tool_by_file(str(file_path))
255
+ try:
256
+ config = yaml.safe_load(open(file_path, "r", encoding="utf-8"))
257
+ self.register_mcp_tool_by_config(config)
258
+ except Exception as e:
259
+ PrettyOutput.print(
260
+ f"文件 {file_path} 加载失败: {str(e)}", OutputType.WARNING
261
+ )
240
262
 
241
263
  def _load_builtin_tools(self) -> None:
242
264
  """从内置工具目录加载工具"""
@@ -264,29 +286,26 @@ class ToolRegistry(OutputHandlerProtocol):
264
286
 
265
287
  self.register_tool_by_file(str(file_path))
266
288
 
267
- def register_mcp_tool_by_file(self, file_path: str) -> bool:
268
- """从指定文件加载并注册工具
289
+ def register_mcp_tool_by_config(self, config: Dict[str, Any]) -> bool:
290
+ """从配置字典加载并注册工具
269
291
 
270
292
  参数:
271
- file_path: 工具文件的路径
293
+ config: MCP工具配置字典
272
294
 
273
295
  返回:
274
296
  bool: 工具是否加载成功
275
297
  """
276
298
  try:
277
- config = yaml.safe_load(open(file_path, "r", encoding="utf-8"))
278
299
  if "type" not in config:
279
- PrettyOutput.print(f"文件 {file_path} 缺少type字段", OutputType.WARNING)
300
+ PrettyOutput.print(f"配置{config.get('name', '')}缺少type字段", OutputType.WARNING)
280
301
  return False
281
302
 
282
303
  # 检查enable标志
283
304
  if not config.get("enable", True):
284
- PrettyOutput.print(
285
- f"文件 {file_path} 已禁用(enable=false),跳过注册", OutputType.INFO
286
- )
305
+ PrettyOutput.print(f"MCP配置{config.get('name', '')}已禁用(enable=false),跳过注册", OutputType.INFO)
287
306
  return False
288
307
 
289
- name = config.get("name", Path(file_path).stem)
308
+ name = config.get("name", "mcp")
290
309
 
291
310
  # 注册资源工具
292
311
  def create_resource_list_func(client: McpClient):
@@ -296,11 +315,11 @@ class ToolRegistry(OutputHandlerProtocol):
296
315
  args.pop("want", None)
297
316
  ret = client.get_resource_list()
298
317
  PrettyOutput.print(
299
- f"MCP {name} 资源列表:\n{yaml.safe_dump(ret)}", OutputType.TOOL
318
+ f"MCP {name} 资源列表:\n{yaml.safe_dump(ret, allow_unicode=True)}", OutputType.TOOL
300
319
  )
301
320
  return {
302
321
  "success": True,
303
- "stdout": yaml.safe_dump(ret),
322
+ "stdout": yaml.safe_dump(ret, allow_unicode=True),
304
323
  "stderr": "",
305
324
  }
306
325
 
@@ -319,7 +338,7 @@ class ToolRegistry(OutputHandlerProtocol):
319
338
  }
320
339
  ret = client.get_resource(args["uri"])
321
340
  PrettyOutput.print(
322
- f"MCP {name} 获取资源:\n{yaml.safe_dump(ret)}", OutputType.TOOL
341
+ f"MCP {name} 获取资源:\n{yaml.safe_dump(ret, allow_unicode=True)}", OutputType.TOOL
323
342
  )
324
343
  return ret
325
344
 
@@ -332,7 +351,7 @@ class ToolRegistry(OutputHandlerProtocol):
332
351
  args.pop("want", None)
333
352
  ret = client.execute(tool_name, args)
334
353
  PrettyOutput.print(
335
- f"MCP {name} {tool_name} 执行结果:\n{yaml.safe_dump(ret)}",
354
+ f"MCP {name} {tool_name} 执行结果:\n{yaml.safe_dump(ret, allow_unicode=True)}",
336
355
  OutputType.TOOL,
337
356
  )
338
357
  return ret
@@ -341,26 +360,18 @@ class ToolRegistry(OutputHandlerProtocol):
341
360
 
342
361
  if config["type"] == "stdio":
343
362
  if "command" not in config:
344
- PrettyOutput.print(
345
- f"文件 {file_path} 缺少command字段", OutputType.WARNING
346
- )
363
+ PrettyOutput.print(f"配置{config.get('name', '')}缺少command字段", OutputType.WARNING)
347
364
  return False
348
365
  elif config["type"] == "sse":
349
366
  if "base_url" not in config:
350
- PrettyOutput.print(
351
- f"文件 {file_path} 缺少base_url字段", OutputType.WARNING
352
- )
367
+ PrettyOutput.print(f"配置{config.get('name', '')}缺少base_url字段", OutputType.WARNING)
353
368
  return False
354
369
  elif config["type"] == "streamable":
355
370
  if "base_url" not in config:
356
- PrettyOutput.print(
357
- f"文件 {file_path} 缺少base_url字段", OutputType.WARNING
358
- )
371
+ PrettyOutput.print(f"配置{config.get('name', '')}缺少base_url字段", OutputType.WARNING)
359
372
  return False
360
373
  else:
361
- PrettyOutput.print(
362
- f"文件 {file_path} 类型错误: {config['type']}", OutputType.WARNING
363
- )
374
+ PrettyOutput.print(f"不支持的MCP客户端类型: {config['type']}", OutputType.WARNING)
364
375
  return False
365
376
 
366
377
  # 创建MCP客户端
@@ -376,14 +387,11 @@ class ToolRegistry(OutputHandlerProtocol):
376
387
  # 获取工具信息
377
388
  tools = mcp_client.get_tool_list()
378
389
  if not tools:
379
- PrettyOutput.print(
380
- f"从 {file_path} 获取工具列表失败", OutputType.WARNING
381
- )
390
+ PrettyOutput.print(f"从配置{config.get('name', '')}获取工具列表失败", OutputType.WARNING)
382
391
  return False
383
392
 
384
393
  # 注册每个工具
385
394
  for tool in tools:
386
-
387
395
  # 注册工具
388
396
  self.register_tool(
389
397
  name=f"{name}.tool_call.{tool['name']}",
@@ -417,9 +425,7 @@ class ToolRegistry(OutputHandlerProtocol):
417
425
  return True
418
426
 
419
427
  except Exception as e:
420
- PrettyOutput.print(
421
- f"文件 {file_path} 加载失败: {str(e)}", OutputType.WARNING
422
- )
428
+ PrettyOutput.print(f"MCP配置{config.get('name', '')}加载失败: {str(e)}", OutputType.WARNING)
423
429
  return False
424
430
 
425
431
  def register_tool_by_file(self, file_path: str) -> bool: