jarvis-ai-assistant 0.1.178__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 +1 -1
- jarvis/jarvis_agent/__init__.py +130 -79
- jarvis/jarvis_agent/builtin_input_handler.py +1 -1
- jarvis/jarvis_agent/jarvis.py +9 -13
- jarvis/jarvis_agent/main.py +4 -2
- jarvis/jarvis_code_agent/code_agent.py +34 -23
- jarvis/jarvis_code_agent/lint.py +164 -0
- jarvis/jarvis_code_analysis/checklists/loader.py +6 -20
- jarvis/jarvis_code_analysis/code_review.py +8 -6
- jarvis/jarvis_data/config_schema.json +260 -0
- jarvis/jarvis_dev/main.py +1 -8
- jarvis/jarvis_git_details/main.py +1 -1
- jarvis/jarvis_git_squash/main.py +5 -3
- jarvis/jarvis_git_utils/git_commiter.py +25 -24
- jarvis/jarvis_mcp/sse_mcp_client.py +6 -4
- jarvis/jarvis_mcp/stdio_mcp_client.py +5 -4
- jarvis/jarvis_mcp/streamable_mcp_client.py +404 -0
- jarvis/jarvis_methodology/main.py +10 -9
- jarvis/jarvis_multi_agent/main.py +3 -1
- jarvis/jarvis_platform/base.py +14 -8
- jarvis/jarvis_platform/human.py +3 -1
- jarvis/jarvis_platform/kimi.py +8 -27
- jarvis/jarvis_platform/openai.py +4 -16
- jarvis/jarvis_platform/registry.py +6 -2
- jarvis/jarvis_platform/yuanbao.py +9 -29
- jarvis/jarvis_platform_manager/main.py +11 -9
- jarvis/jarvis_smart_shell/main.py +7 -3
- jarvis/jarvis_tools/ask_codebase.py +4 -3
- jarvis/jarvis_tools/ask_user.py +2 -1
- jarvis/jarvis_tools/base.py +3 -1
- jarvis/jarvis_tools/chdir.py +2 -1
- jarvis/jarvis_tools/cli/main.py +1 -0
- jarvis/jarvis_tools/code_plan.py +5 -3
- jarvis/jarvis_tools/create_code_agent.py +5 -2
- jarvis/jarvis_tools/create_sub_agent.py +1 -3
- jarvis/jarvis_tools/edit_file.py +4 -4
- jarvis/jarvis_tools/execute_script.py +1 -1
- jarvis/jarvis_tools/file_analyzer.py +5 -3
- jarvis/jarvis_tools/file_operation.py +4 -7
- jarvis/jarvis_tools/find_methodology.py +4 -2
- jarvis/jarvis_tools/generate_new_tool.py +2 -1
- jarvis/jarvis_tools/methodology.py +3 -4
- jarvis/jarvis_tools/read_code.py +2 -1
- jarvis/jarvis_tools/read_webpage.py +3 -1
- jarvis/jarvis_tools/registry.py +60 -45
- jarvis/jarvis_tools/rewrite_file.py +2 -1
- jarvis/jarvis_tools/search_web.py +1 -0
- jarvis/jarvis_tools/virtual_tty.py +5 -4
- jarvis/jarvis_utils/__init__.py +2 -0
- jarvis/jarvis_utils/builtin_replace_map.py +1 -1
- jarvis/jarvis_utils/config.py +88 -17
- jarvis/jarvis_utils/embedding.py +4 -3
- jarvis/jarvis_utils/file_processors.py +1 -0
- jarvis/jarvis_utils/git_utils.py +83 -40
- jarvis/jarvis_utils/globals.py +4 -2
- jarvis/jarvis_utils/input.py +14 -7
- jarvis/jarvis_utils/methodology.py +6 -4
- jarvis/jarvis_utils/output.py +10 -6
- jarvis/jarvis_utils/utils.py +140 -24
- {jarvis_ai_assistant-0.1.178.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/METADATA +66 -59
- jarvis_ai_assistant-0.1.180.dist-info/RECORD +99 -0
- jarvis_ai_assistant-0.1.178.dist-info/RECORD +0 -96
- {jarvis_ai_assistant-0.1.178.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.178.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.178.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.178.dist-info → jarvis_ai_assistant-0.1.180.dist-info}/top_level.txt +0 -0
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
import
|
|
2
|
+
import hashlib
|
|
3
|
+
import hmac
|
|
4
4
|
import json
|
|
5
5
|
import os
|
|
6
|
-
import hmac
|
|
7
|
-
import hashlib
|
|
8
6
|
import time
|
|
9
7
|
import urllib.parse
|
|
8
|
+
from typing import Dict, Generator, List, Tuple
|
|
9
|
+
|
|
10
|
+
import requests
|
|
10
11
|
from PIL import Image
|
|
11
12
|
from yaspin import yaspin
|
|
12
|
-
from yaspin.spinners import Spinners
|
|
13
13
|
from yaspin.api import Yaspin
|
|
14
|
-
from
|
|
15
|
-
|
|
16
|
-
from rich.panel import Panel
|
|
17
|
-
from rich import box
|
|
14
|
+
from yaspin.spinners import Spinners
|
|
15
|
+
|
|
18
16
|
from jarvis.jarvis_platform.base import BasePlatform
|
|
17
|
+
from jarvis.jarvis_utils.config import get_data_dir
|
|
19
18
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
20
19
|
from jarvis.jarvis_utils.utils import while_success
|
|
21
|
-
|
|
20
|
+
|
|
22
21
|
|
|
23
22
|
class YuanbaoPlatform(BasePlatform):
|
|
24
23
|
"""Hunyuan模型实现"""
|
|
@@ -40,25 +39,6 @@ class YuanbaoPlatform(BasePlatform):
|
|
|
40
39
|
self.agent_id = os.getenv("YUANBAO_AGENT_ID") # 代理ID
|
|
41
40
|
|
|
42
41
|
if not self.cookies:
|
|
43
|
-
message = (
|
|
44
|
-
"需要设置 YUANBAO_COOKIES 和 YUANBAO_AGENT_ID 才能使用 Jarvis 的元宝功能。请按照以下步骤操作:\n"
|
|
45
|
-
"1. 获取元宝 API 参数:\n"
|
|
46
|
-
" • 访问元宝平台: https://yuanbao.tencent.com\n"
|
|
47
|
-
" • 登录您的账户\n"
|
|
48
|
-
" • 打开浏览器开发者工具 (F12 或右键 -> 检查)\n"
|
|
49
|
-
" • 切换到网络标签\n"
|
|
50
|
-
" • 发送任意消息\n"
|
|
51
|
-
" • 查看请求中的 Cookie 和 AgentID 值(具体位置见README.md中截图)\n"
|
|
52
|
-
"2. 设置环境变量:\n"
|
|
53
|
-
" • 方法 1: 创建或编辑配置文件:\n"
|
|
54
|
-
f" echo 'YUANBAO_COOKIES=your_cookies_here' >> {get_data_dir()}/env\n"
|
|
55
|
-
f" echo 'YUANBAO_AGENT_ID=your_agent_id_here' >> {get_data_dir()}/env\n"
|
|
56
|
-
" • 方法 2: 直接设置环境变量:\n"
|
|
57
|
-
" export YUANBAO_COOKIES=your_cookies_here\n"
|
|
58
|
-
" export YUANBAO_AGENT_ID=your_agent_id_here\n"
|
|
59
|
-
"设置后,重新运行 Jarvis。"
|
|
60
|
-
)
|
|
61
|
-
PrettyOutput.print(message, OutputType.INFO)
|
|
62
42
|
PrettyOutput.print("YUANBAO_COOKIES 未设置", OutputType.WARNING)
|
|
63
43
|
|
|
64
44
|
self.system_message = "" # 系统消息,用于初始化对话
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
import os
|
|
3
|
-
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
4
2
|
import asyncio
|
|
3
|
+
import os
|
|
4
|
+
from typing import Any, Dict, List, Optional
|
|
5
|
+
|
|
6
|
+
import uvicorn
|
|
5
7
|
from fastapi import FastAPI, HTTPException
|
|
8
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
6
9
|
from fastapi.responses import StreamingResponse
|
|
7
10
|
from pydantic import BaseModel, Field
|
|
8
|
-
from typing import List, Dict, Any, Optional
|
|
9
|
-
import uvicorn
|
|
10
|
-
from fastapi.middleware.cors import CORSMiddleware
|
|
11
11
|
|
|
12
|
+
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
12
13
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
13
14
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
14
15
|
from jarvis.jarvis_utils.utils import init_env
|
|
15
16
|
|
|
17
|
+
|
|
16
18
|
def list_platforms():
|
|
17
19
|
"""List all supported platforms and models"""
|
|
18
20
|
registry = PlatformRegistry.get_global_platform_registry()
|
|
@@ -248,10 +250,10 @@ class ChatCompletionResponse(BaseModel):
|
|
|
248
250
|
|
|
249
251
|
def service_command(args):
|
|
250
252
|
"""Process service subcommand - start OpenAI-compatible API server"""
|
|
251
|
-
import time
|
|
252
|
-
import uuid
|
|
253
253
|
import json
|
|
254
254
|
import os
|
|
255
|
+
import time
|
|
256
|
+
import uuid
|
|
255
257
|
from datetime import datetime
|
|
256
258
|
|
|
257
259
|
host = args.host
|
|
@@ -451,11 +453,11 @@ def service_command(args):
|
|
|
451
453
|
|
|
452
454
|
async def stream_chat_response(platform, message, model_name):
|
|
453
455
|
"""Stream chat response in OpenAI-compatible format"""
|
|
454
|
-
import time
|
|
455
456
|
import json
|
|
457
|
+
import os
|
|
458
|
+
import time
|
|
456
459
|
import uuid
|
|
457
460
|
from datetime import datetime
|
|
458
|
-
import os
|
|
459
461
|
|
|
460
462
|
completion_id = f"chatcmpl-{str(uuid.uuid4())}"
|
|
461
463
|
created_time = int(time.time())
|
|
@@ -8,10 +8,11 @@ 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
|
|
|
15
|
+
|
|
15
16
|
def execute_command(command: str, should_run: bool) -> None:
|
|
16
17
|
"""Print command without execution"""
|
|
17
18
|
print(command)
|
|
@@ -89,7 +90,7 @@ def process_request(request: str) -> Optional[str]:
|
|
|
89
90
|
|
|
90
91
|
# 规则
|
|
91
92
|
1. 只输出命令
|
|
92
|
-
2.
|
|
93
|
+
2. 不要输出任何命令之外的内容
|
|
93
94
|
3. 单行输出
|
|
94
95
|
4. 多个命令用&&连接
|
|
95
96
|
|
|
@@ -115,8 +116,11 @@ def process_request(request: str) -> Optional[str]:
|
|
|
115
116
|
return None
|
|
116
117
|
|
|
117
118
|
def main() -> int:
|
|
118
|
-
# 创建参数解析器
|
|
119
|
+
# 创建参数解析器
|
|
119
120
|
init_env("")
|
|
121
|
+
|
|
122
|
+
set_config("JARVIS_PRINT_PROMPT", "false")
|
|
123
|
+
|
|
120
124
|
parser = argparse.ArgumentParser(
|
|
121
125
|
description="将自然语言要求转换为shell命令",
|
|
122
126
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import Dict, Any
|
|
3
2
|
import os
|
|
4
|
-
|
|
3
|
+
from typing import Any, Dict
|
|
5
4
|
|
|
6
5
|
from jarvis.jarvis_agent import Agent
|
|
7
6
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
8
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
9
7
|
from jarvis.jarvis_utils.git_utils import find_git_root
|
|
8
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
10
9
|
from jarvis.jarvis_utils.utils import init_env
|
|
11
10
|
|
|
11
|
+
|
|
12
12
|
class AskCodebaseTool:
|
|
13
13
|
"""用于智能代码库查询和分析的工具
|
|
14
14
|
|
|
@@ -258,6 +258,7 @@ def main():
|
|
|
258
258
|
"""
|
|
259
259
|
import argparse
|
|
260
260
|
import sys
|
|
261
|
+
|
|
261
262
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
262
263
|
|
|
263
264
|
init_env("欢迎使用 Jarvis-AskCodebase,您的智能代码库查询工具已准备就绪!")
|
jarvis/jarvis_tools/ask_user.py
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# 导入所需的类型注解模块
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Any, Dict
|
|
4
4
|
|
|
5
5
|
# 导入多行输入工具和输出工具
|
|
6
6
|
from jarvis.jarvis_utils.input import get_multiline_input
|
|
7
7
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
8
8
|
|
|
9
|
+
|
|
9
10
|
# 定义AskUserTool类,用于向用户提问
|
|
10
11
|
class AskUserTool:
|
|
11
12
|
name="ask_user"
|
jarvis/jarvis_tools/base.py
CHANGED
jarvis/jarvis_tools/chdir.py
CHANGED
jarvis/jarvis_tools/cli/main.py
CHANGED
jarvis/jarvis_tools/code_plan.py
CHANGED
|
@@ -9,13 +9,15 @@
|
|
|
9
9
|
4. 修改计划输出
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
-
from typing import Dict, Any
|
|
13
12
|
import os
|
|
14
|
-
from
|
|
13
|
+
from typing import Any, Dict
|
|
14
|
+
|
|
15
15
|
from jarvis.jarvis_agent import Agent
|
|
16
16
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
17
|
-
from jarvis.
|
|
17
|
+
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
18
18
|
from jarvis.jarvis_utils.git_utils import find_git_root
|
|
19
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
20
|
+
|
|
19
21
|
|
|
20
22
|
class CodePlanTool:
|
|
21
23
|
"""用于代码修改规划和需求分析的工具
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import Dict, Any
|
|
3
2
|
import os
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
|
|
4
5
|
from jarvis.jarvis_code_agent.code_agent import CodeAgent
|
|
5
6
|
from jarvis.jarvis_git_utils.git_commiter import GitCommitTool
|
|
6
|
-
from jarvis.jarvis_utils.git_utils import get_latest_commit_hash,
|
|
7
|
+
from jarvis.jarvis_utils.git_utils import (get_latest_commit_hash,
|
|
8
|
+
has_uncommitted_changes)
|
|
7
9
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
8
10
|
|
|
11
|
+
|
|
9
12
|
class CreateCodeAgentTool:
|
|
10
13
|
"""用于管理代码开发工作流的工具"""
|
|
11
14
|
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import Dict, Any
|
|
3
2
|
import os
|
|
4
|
-
|
|
3
|
+
from typing import Any, Dict
|
|
5
4
|
|
|
6
5
|
from jarvis.jarvis_agent import Agent, origin_agent_system_prompt
|
|
7
6
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
|
|
11
9
|
class SubAgentTool:
|
|
12
10
|
name = "create_sub_agent"
|
|
13
11
|
description = "创建子代理以处理特定任务,子代理将生成任务总结报告"
|
jarvis/jarvis_tools/edit_file.py
CHANGED
|
@@ -17,9 +17,8 @@
|
|
|
17
17
|
- 支持大文件处理(自动上传到模型平台)
|
|
18
18
|
- 提供3次重试机制确保操作可靠性
|
|
19
19
|
"""
|
|
20
|
-
from typing import List
|
|
21
20
|
import re
|
|
22
|
-
from typing import Any, Dict, Tuple
|
|
21
|
+
from typing import Any, Dict, List, Tuple
|
|
23
22
|
|
|
24
23
|
import yaml
|
|
25
24
|
from yaspin import yaspin
|
|
@@ -130,7 +129,8 @@ class FileSearchReplaceTool:
|
|
|
130
129
|
4. 保持原始代码的格式风格
|
|
131
130
|
"""
|
|
132
131
|
import os
|
|
133
|
-
|
|
132
|
+
|
|
133
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
134
134
|
|
|
135
135
|
stdout_messages = []
|
|
136
136
|
stderr_messages = []
|
|
@@ -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):
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import Dict, Any
|
|
3
2
|
import os
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
|
|
5
|
+
from yaspin import yaspin # type: ignore
|
|
6
|
+
from yaspin.spinners import Spinners # type: ignore
|
|
4
7
|
|
|
5
8
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
6
9
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
7
|
-
|
|
8
|
-
from yaspin.spinners import Spinners # type: ignore
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
class FileAnalyzerTool:
|
|
11
13
|
name = "file_analyzer"
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import Dict, Any
|
|
3
2
|
import os
|
|
4
3
|
from pathlib import Path
|
|
4
|
+
from typing import Any, Dict
|
|
5
5
|
|
|
6
|
-
from yaspin import yaspin
|
|
6
|
+
from yaspin import yaspin # type: ignore
|
|
7
7
|
|
|
8
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
9
8
|
# 导入文件处理器
|
|
10
|
-
from jarvis.jarvis_utils.file_processors import
|
|
11
|
-
|
|
12
|
-
)
|
|
13
|
-
|
|
9
|
+
from jarvis.jarvis_utils.file_processors import TextFileProcessor
|
|
10
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
14
11
|
|
|
15
12
|
|
|
16
13
|
class FileOperationTool:
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
|
|
3
4
|
from yaspin import yaspin
|
|
4
5
|
|
|
5
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
6
6
|
from jarvis.jarvis_utils.methodology import load_methodology
|
|
7
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
class FindMethodologyTool:
|
|
9
11
|
name = "find_methodology"
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
import re
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Any, Dict, Tuple
|
|
5
5
|
|
|
6
6
|
from jarvis.jarvis_utils.config import get_data_dir
|
|
7
7
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
8
8
|
|
|
9
|
+
|
|
9
10
|
class generate_new_tool:
|
|
10
11
|
name = "generate_new_tool"
|
|
11
12
|
description = """
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
import os
|
|
3
|
-
import json
|
|
4
2
|
import hashlib
|
|
5
|
-
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from typing import Any, Dict
|
|
6
6
|
|
|
7
7
|
from jarvis.jarvis_utils.config import get_data_dir
|
|
8
8
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
class MethodologyTool:
|
|
13
12
|
"""经验管理工具"""
|
|
14
13
|
|
jarvis/jarvis_tools/read_code.py
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import Dict, Any
|
|
3
2
|
import os
|
|
3
|
+
from typing import Any, Dict
|
|
4
4
|
|
|
5
5
|
from yaspin import yaspin
|
|
6
6
|
|
|
7
7
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
8
8
|
|
|
9
|
+
|
|
9
10
|
class ReadCodeTool:
|
|
10
11
|
name = "read_code"
|
|
11
12
|
description = "代码阅读与分析工具,用于读取源代码文件并添加行号,针对代码文件优化,提供更好的格式化输出和行号显示,适用于代码分析、审查和理解代码实现的场景"
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import Dict, Any
|
|
3
2
|
import os
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
|
|
4
5
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
5
6
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
6
7
|
|
|
8
|
+
|
|
7
9
|
class WebpageTool:
|
|
8
10
|
name = "read_webpage"
|
|
9
11
|
description = "读取网页内容,提取标题、文本和超链接"
|
jarvis/jarvis_tools/registry.py
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
import json
|
|
3
|
-
|
|
3
|
+
import os
|
|
4
4
|
import re
|
|
5
5
|
import sys
|
|
6
6
|
import tempfile
|
|
7
|
-
import
|
|
8
|
-
from typing import Any, Callable, Dict, List, Optional,
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Callable, Dict, List, Optional, Protocol, Tuple
|
|
9
9
|
|
|
10
10
|
import yaml
|
|
11
11
|
|
|
12
|
+
from jarvis.jarvis_mcp import McpClient
|
|
13
|
+
from jarvis.jarvis_mcp.sse_mcp_client import SSEMcpClient
|
|
14
|
+
from jarvis.jarvis_mcp.stdio_mcp_client import StdioMcpClient
|
|
15
|
+
from jarvis.jarvis_mcp.streamable_mcp_client import StreamableMcpClient
|
|
12
16
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
13
17
|
from jarvis.jarvis_tools.base import Tool
|
|
14
18
|
from jarvis.jarvis_utils.config import get_data_dir
|
|
15
19
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
20
|
+
from jarvis.jarvis_utils.tag import ct, ot
|
|
16
21
|
from jarvis.jarvis_utils.utils import init_env, is_context_overflow
|
|
17
|
-
from jarvis.jarvis_utils.tag import ot, ct
|
|
18
|
-
from jarvis.jarvis_mcp.stdio_mcp_client import StdioMcpClient
|
|
19
|
-
from jarvis.jarvis_mcp.sse_mcp_client import SSEMcpClient
|
|
20
|
-
from jarvis.jarvis_mcp import McpClient
|
|
21
|
-
|
|
22
22
|
|
|
23
23
|
tool_call_help = f"""
|
|
24
24
|
<tool_system_guide>
|
|
@@ -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
|
-
"""
|
|
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
|
-
|
|
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
|
|
268
|
-
"""
|
|
289
|
+
def register_mcp_tool_by_config(self, config: Dict[str, Any]) -> bool:
|
|
290
|
+
"""从配置字典加载并注册工具
|
|
269
291
|
|
|
270
292
|
参数:
|
|
271
|
-
|
|
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"
|
|
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",
|
|
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,40 +360,38 @@ 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
|
-
|
|
352
|
-
|
|
367
|
+
PrettyOutput.print(f"配置{config.get('name', '')}缺少base_url字段", OutputType.WARNING)
|
|
368
|
+
return False
|
|
369
|
+
elif config["type"] == "streamable":
|
|
370
|
+
if "base_url" not in config:
|
|
371
|
+
PrettyOutput.print(f"配置{config.get('name', '')}缺少base_url字段", OutputType.WARNING)
|
|
353
372
|
return False
|
|
354
373
|
else:
|
|
355
|
-
PrettyOutput.print(
|
|
356
|
-
f"文件 {file_path} 类型错误: {config['type']}", OutputType.WARNING
|
|
357
|
-
)
|
|
374
|
+
PrettyOutput.print(f"不支持的MCP客户端类型: {config['type']}", OutputType.WARNING)
|
|
358
375
|
return False
|
|
359
376
|
|
|
360
377
|
# 创建MCP客户端
|
|
361
|
-
|
|
362
|
-
StdioMcpClient(config)
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
378
|
+
if config["type"] == "stdio":
|
|
379
|
+
mcp_client: McpClient = StdioMcpClient(config)
|
|
380
|
+
elif config["type"] == "sse":
|
|
381
|
+
mcp_client: McpClient = SSEMcpClient(config)
|
|
382
|
+
elif config["type"] == "streamable":
|
|
383
|
+
mcp_client: McpClient = StreamableMcpClient(config)
|
|
384
|
+
else:
|
|
385
|
+
raise ValueError(f"不支持的MCP客户端类型: {config['type']}")
|
|
366
386
|
|
|
367
387
|
# 获取工具信息
|
|
368
388
|
tools = mcp_client.get_tool_list()
|
|
369
389
|
if not tools:
|
|
370
|
-
PrettyOutput.print(
|
|
371
|
-
f"从 {file_path} 获取工具列表失败", OutputType.WARNING
|
|
372
|
-
)
|
|
390
|
+
PrettyOutput.print(f"从配置{config.get('name', '')}获取工具列表失败", OutputType.WARNING)
|
|
373
391
|
return False
|
|
374
392
|
|
|
375
393
|
# 注册每个工具
|
|
376
394
|
for tool in tools:
|
|
377
|
-
|
|
378
395
|
# 注册工具
|
|
379
396
|
self.register_tool(
|
|
380
397
|
name=f"{name}.tool_call.{tool['name']}",
|
|
@@ -408,9 +425,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
|
408
425
|
return True
|
|
409
426
|
|
|
410
427
|
except Exception as e:
|
|
411
|
-
PrettyOutput.print(
|
|
412
|
-
f"文件 {file_path} 加载失败: {str(e)}", OutputType.WARNING
|
|
413
|
-
)
|
|
428
|
+
PrettyOutput.print(f"MCP配置{config.get('name', '')}加载失败: {str(e)}", OutputType.WARNING)
|
|
414
429
|
return False
|
|
415
430
|
|
|
416
431
|
def register_tool_by_file(self, file_path: str) -> bool:
|