jarvis-ai-assistant 0.3.30__py3-none-any.whl → 0.7.6__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +458 -152
- jarvis/jarvis_agent/agent_manager.py +17 -13
- jarvis/jarvis_agent/builtin_input_handler.py +2 -6
- jarvis/jarvis_agent/config_editor.py +2 -7
- jarvis/jarvis_agent/event_bus.py +82 -12
- jarvis/jarvis_agent/file_context_handler.py +329 -0
- jarvis/jarvis_agent/file_methodology_manager.py +3 -4
- jarvis/jarvis_agent/jarvis.py +628 -55
- jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
- jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
- jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
- jarvis/jarvis_agent/language_support_info.py +486 -0
- jarvis/jarvis_agent/main.py +34 -10
- jarvis/jarvis_agent/memory_manager.py +7 -16
- jarvis/jarvis_agent/methodology_share_manager.py +10 -16
- jarvis/jarvis_agent/prompt_manager.py +1 -1
- jarvis/jarvis_agent/prompts.py +193 -171
- jarvis/jarvis_agent/protocols.py +8 -12
- jarvis/jarvis_agent/run_loop.py +105 -9
- jarvis/jarvis_agent/session_manager.py +2 -3
- jarvis/jarvis_agent/share_manager.py +20 -22
- jarvis/jarvis_agent/shell_input_handler.py +1 -2
- jarvis/jarvis_agent/stdio_redirect.py +295 -0
- jarvis/jarvis_agent/task_analyzer.py +31 -6
- jarvis/jarvis_agent/task_manager.py +11 -27
- jarvis/jarvis_agent/tool_executor.py +2 -3
- jarvis/jarvis_agent/tool_share_manager.py +12 -24
- jarvis/jarvis_agent/utils.py +5 -1
- jarvis/jarvis_agent/web_bridge.py +189 -0
- jarvis/jarvis_agent/web_output_sink.py +53 -0
- jarvis/jarvis_agent/web_server.py +786 -0
- jarvis/jarvis_c2rust/__init__.py +26 -0
- jarvis/jarvis_c2rust/cli.py +575 -0
- jarvis/jarvis_c2rust/collector.py +250 -0
- jarvis/jarvis_c2rust/constants.py +26 -0
- jarvis/jarvis_c2rust/library_replacer.py +1254 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +1272 -0
- jarvis/jarvis_c2rust/loaders.py +207 -0
- jarvis/jarvis_c2rust/models.py +28 -0
- jarvis/jarvis_c2rust/optimizer.py +2157 -0
- jarvis/jarvis_c2rust/scanner.py +1681 -0
- jarvis/jarvis_c2rust/transpiler.py +2983 -0
- jarvis/jarvis_c2rust/utils.py +385 -0
- jarvis/jarvis_code_agent/build_validation_config.py +132 -0
- jarvis/jarvis_code_agent/code_agent.py +1371 -220
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +65 -0
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +106 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +72 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +70 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +53 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +47 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +61 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +154 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +153 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +648 -0
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +49 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +299 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +215 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +269 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +281 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +605 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +252 -0
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +58 -0
- jarvis/jarvis_code_agent/lint.py +501 -8
- jarvis/jarvis_code_agent/utils.py +141 -0
- jarvis/jarvis_code_analysis/code_review.py +493 -584
- jarvis/jarvis_data/config_schema.json +128 -12
- jarvis/jarvis_git_squash/main.py +4 -5
- jarvis/jarvis_git_utils/git_commiter.py +82 -75
- jarvis/jarvis_mcp/sse_mcp_client.py +22 -29
- jarvis/jarvis_mcp/stdio_mcp_client.py +12 -13
- jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
- jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
- jarvis/jarvis_methodology/main.py +32 -48
- jarvis/jarvis_multi_agent/__init__.py +287 -55
- jarvis/jarvis_multi_agent/main.py +36 -4
- jarvis/jarvis_platform/base.py +524 -202
- jarvis/jarvis_platform/human.py +7 -8
- jarvis/jarvis_platform/kimi.py +30 -36
- jarvis/jarvis_platform/openai.py +88 -25
- jarvis/jarvis_platform/registry.py +26 -10
- jarvis/jarvis_platform/tongyi.py +24 -25
- jarvis/jarvis_platform/yuanbao.py +32 -43
- jarvis/jarvis_platform_manager/main.py +66 -77
- jarvis/jarvis_platform_manager/service.py +8 -13
- jarvis/jarvis_rag/cli.py +53 -55
- jarvis/jarvis_rag/embedding_manager.py +13 -18
- jarvis/jarvis_rag/llm_interface.py +8 -9
- jarvis/jarvis_rag/query_rewriter.py +10 -21
- jarvis/jarvis_rag/rag_pipeline.py +24 -27
- jarvis/jarvis_rag/reranker.py +4 -5
- jarvis/jarvis_rag/retriever.py +28 -30
- jarvis/jarvis_sec/__init__.py +305 -0
- jarvis/jarvis_sec/agents.py +143 -0
- jarvis/jarvis_sec/analysis.py +276 -0
- jarvis/jarvis_sec/checkers/__init__.py +32 -0
- jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
- jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
- jarvis/jarvis_sec/cli.py +139 -0
- jarvis/jarvis_sec/clustering.py +1439 -0
- jarvis/jarvis_sec/file_manager.py +427 -0
- jarvis/jarvis_sec/parsers.py +73 -0
- jarvis/jarvis_sec/prompts.py +268 -0
- jarvis/jarvis_sec/report.py +336 -0
- jarvis/jarvis_sec/review.py +453 -0
- jarvis/jarvis_sec/status.py +264 -0
- jarvis/jarvis_sec/types.py +20 -0
- jarvis/jarvis_sec/utils.py +499 -0
- jarvis/jarvis_sec/verification.py +848 -0
- jarvis/jarvis_sec/workflow.py +226 -0
- jarvis/jarvis_smart_shell/main.py +38 -87
- jarvis/jarvis_stats/cli.py +2 -2
- jarvis/jarvis_stats/stats.py +8 -8
- jarvis/jarvis_stats/storage.py +15 -21
- jarvis/jarvis_stats/visualizer.py +1 -1
- jarvis/jarvis_tools/clear_memory.py +3 -20
- jarvis/jarvis_tools/cli/main.py +21 -23
- jarvis/jarvis_tools/edit_file.py +1019 -132
- jarvis/jarvis_tools/execute_script.py +83 -25
- jarvis/jarvis_tools/file_analyzer.py +6 -9
- jarvis/jarvis_tools/generate_new_tool.py +14 -21
- jarvis/jarvis_tools/lsp_client.py +1552 -0
- jarvis/jarvis_tools/methodology.py +2 -3
- jarvis/jarvis_tools/read_code.py +1736 -35
- jarvis/jarvis_tools/read_symbols.py +140 -0
- jarvis/jarvis_tools/read_webpage.py +12 -13
- jarvis/jarvis_tools/registry.py +427 -200
- jarvis/jarvis_tools/retrieve_memory.py +20 -19
- jarvis/jarvis_tools/rewrite_file.py +72 -158
- jarvis/jarvis_tools/save_memory.py +3 -15
- jarvis/jarvis_tools/search_web.py +18 -18
- jarvis/jarvis_tools/sub_agent.py +36 -43
- jarvis/jarvis_tools/sub_code_agent.py +25 -26
- jarvis/jarvis_tools/virtual_tty.py +55 -33
- jarvis/jarvis_utils/clipboard.py +7 -10
- jarvis/jarvis_utils/config.py +232 -45
- jarvis/jarvis_utils/embedding.py +8 -5
- jarvis/jarvis_utils/fzf.py +8 -8
- jarvis/jarvis_utils/git_utils.py +225 -36
- jarvis/jarvis_utils/globals.py +3 -3
- jarvis/jarvis_utils/http.py +1 -1
- jarvis/jarvis_utils/input.py +99 -48
- jarvis/jarvis_utils/jsonnet_compat.py +465 -0
- jarvis/jarvis_utils/methodology.py +52 -48
- jarvis/jarvis_utils/utils.py +819 -491
- jarvis_ai_assistant-0.7.6.dist-info/METADATA +600 -0
- jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +4 -0
- jarvis/jarvis_agent/config.py +0 -92
- jarvis/jarvis_agent/edit_file_handler.py +0 -296
- jarvis/jarvis_platform/ai8.py +0 -332
- jarvis/jarvis_tools/ask_user.py +0 -54
- jarvis_ai_assistant-0.3.30.dist-info/METADATA +0 -381
- jarvis_ai_assistant-0.3.30.dist-info/RECORD +0 -137
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
|
@@ -4,7 +4,6 @@ from pathlib import Path
|
|
|
4
4
|
from typing import Any, Dict, List, Optional
|
|
5
5
|
|
|
6
6
|
from jarvis.jarvis_utils.config import get_data_dir, get_max_input_token_count
|
|
7
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
8
7
|
from jarvis.jarvis_utils.globals import get_short_term_memories
|
|
9
8
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
|
10
9
|
|
|
@@ -13,17 +12,7 @@ class RetrieveMemoryTool:
|
|
|
13
12
|
"""检索记忆工具,用于从长短期记忆系统中检索信息"""
|
|
14
13
|
|
|
15
14
|
name = "retrieve_memory"
|
|
16
|
-
description = ""
|
|
17
|
-
|
|
18
|
-
支持的记忆类型:
|
|
19
|
-
- project_long_term: 项目长期记忆(与当前项目相关的信息)
|
|
20
|
-
- global_long_term: 全局长期记忆(通用的信息、用户喜好、知识、方法等)
|
|
21
|
-
- short_term: 短期记忆(当前任务相关的信息)
|
|
22
|
-
- all: 从所有类型中检索
|
|
23
|
-
|
|
24
|
-
可以通过标签过滤检索结果,支持多个标签(满足任一标签即可)
|
|
25
|
-
注意:标签数量建议不要超过10个,以保证检索效率
|
|
26
|
-
"""
|
|
15
|
+
description = "从长短期记忆系统中检索信息。支持按类型(project_long_term/global_long_term/short_term/all)和标签过滤,标签建议不超过10个。"
|
|
27
16
|
|
|
28
17
|
parameters = {
|
|
29
18
|
"type": "object",
|
|
@@ -99,9 +88,7 @@ class RetrieveMemoryTool:
|
|
|
99
88
|
|
|
100
89
|
memories.append(memory_data)
|
|
101
90
|
except Exception as e:
|
|
102
|
-
|
|
103
|
-
f"读取记忆文件 {memory_file} 失败: {str(e)}", OutputType.WARNING
|
|
104
|
-
)
|
|
91
|
+
print(f"⚠️ 读取记忆文件 {memory_file} 失败: {str(e)}")
|
|
105
92
|
|
|
106
93
|
return memories
|
|
107
94
|
|
|
@@ -131,9 +118,23 @@ class RetrieveMemoryTool:
|
|
|
131
118
|
# 按创建时间排序(最新的在前)
|
|
132
119
|
all_memories.sort(key=lambda x: x.get("created_at", ""), reverse=True)
|
|
133
120
|
|
|
134
|
-
#
|
|
135
|
-
|
|
136
|
-
|
|
121
|
+
# 优先使用剩余token数量,回退到输入窗口限制
|
|
122
|
+
memory_token_limit = None
|
|
123
|
+
agent = args.get("agent")
|
|
124
|
+
if agent and hasattr(agent, "model"):
|
|
125
|
+
try:
|
|
126
|
+
remaining_tokens = agent.model.get_remaining_token_count()
|
|
127
|
+
# 使用剩余token的2/3作为限制,保留1/3作为安全余量
|
|
128
|
+
memory_token_limit = int(remaining_tokens * 2 / 3)
|
|
129
|
+
if memory_token_limit <= 0:
|
|
130
|
+
memory_token_limit = None
|
|
131
|
+
except Exception:
|
|
132
|
+
pass
|
|
133
|
+
|
|
134
|
+
# 回退方案:使用输入窗口的2/3
|
|
135
|
+
if memory_token_limit is None:
|
|
136
|
+
max_input_tokens = get_max_input_token_count()
|
|
137
|
+
memory_token_limit = int(max_input_tokens * 2 / 3)
|
|
137
138
|
|
|
138
139
|
# 基于token限制和条数限制筛选记忆
|
|
139
140
|
filtered_memories: List[Dict[str, Any]] = []
|
|
@@ -223,5 +224,5 @@ class RetrieveMemoryTool:
|
|
|
223
224
|
|
|
224
225
|
except Exception as e:
|
|
225
226
|
error_msg = f"检索记忆失败: {str(e)}"
|
|
226
|
-
|
|
227
|
+
print(f"❌ {error_msg}")
|
|
227
228
|
return {"success": False, "stdout": "", "stderr": error_msg}
|
|
@@ -1,191 +1,105 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
文件重写工具类
|
|
4
|
-
|
|
5
|
-
功能概述:
|
|
6
|
-
1. 提供完整的文件重写功能
|
|
7
|
-
2. 支持创建新文件或完全重写现有文件
|
|
8
|
-
3. 实现原子操作:所有修改要么全部成功,要么全部回滚
|
|
9
|
-
4. 自动创建所需目录结构
|
|
10
|
-
|
|
11
|
-
核心特性:
|
|
12
|
-
- 支持不存在的文件和空文件处理
|
|
13
|
-
- 自动创建所需目录结构
|
|
14
|
-
- 完善的错误处理和回滚机制
|
|
15
|
-
- 保持文件格式和编码
|
|
16
|
-
"""
|
|
2
|
+
import os
|
|
17
3
|
from typing import Any, Dict
|
|
18
4
|
|
|
19
5
|
|
|
20
|
-
|
|
6
|
+
|
|
7
|
+
class RewriteFileTool:
|
|
8
|
+
"""文件重写工具,用于完全重写文件内容"""
|
|
9
|
+
|
|
21
10
|
name = "rewrite_file"
|
|
22
|
-
description = ""
|
|
23
|
-
|
|
24
|
-
# 文件重写规范
|
|
25
|
-
|
|
26
|
-
## 重要提示
|
|
27
|
-
此工具用于完全重写文件内容或创建新文件。与edit_file不同,此工具会替换文件的全部内容。
|
|
28
|
-
|
|
29
|
-
## 基本使用
|
|
30
|
-
1. 指定需要重写的文件路径
|
|
31
|
-
2. 提供新的文件内容
|
|
32
|
-
3. 所有操作要么全部成功,要么全部失败并回滚
|
|
33
|
-
|
|
34
|
-
## 核心原则
|
|
35
|
-
1. **完整重写**:提供完整的文件内容,将替换原文件的所有内容
|
|
36
|
-
2. **格式保持**:
|
|
37
|
-
- 保持原始代码的缩进方式(空格或制表符)
|
|
38
|
-
- 保持原始代码的空行数量和位置
|
|
39
|
-
- 保持原始代码的行尾空格处理方式
|
|
40
|
-
- 不改变原始代码的换行风格
|
|
41
|
-
|
|
42
|
-
## 最佳实践
|
|
43
|
-
1. 确保提供格式良好的完整文件内容
|
|
44
|
-
2. 创建新文件时提供完整、格式良好的内容
|
|
45
|
-
3. 不要出现未实现的代码,如:TODO
|
|
46
|
-
"""
|
|
11
|
+
description = "完全重写文件内容,适用于新增文件或大范围改写。具备失败回滚能力。局部修改请使用 edit_file。\n\n ⚠️ 重要提示:\n - 不要一次重写太多内容,建议分多次进行,避免超过LLM的上下文窗口大小\n - 如果文件内容较长(超过2048字符),建议采用以下策略:\n 1. 第一次调用 rewrite_file 写入部分内容(如文件的前半部分或关键部分)\n 2. 然后多次调用 edit_file 工具,使用 insert_after 操作补充后续内容\n - 这样可以避免单次操作内容过长导致上下文溢出"
|
|
12
|
+
|
|
47
13
|
parameters = {
|
|
48
14
|
"type": "object",
|
|
49
15
|
"properties": {
|
|
50
|
-
"
|
|
16
|
+
"file_path": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "要重写的文件路径(支持绝对路径和相对路径)",
|
|
19
|
+
},
|
|
51
20
|
"content": {
|
|
52
21
|
"type": "string",
|
|
53
|
-
"description": "
|
|
22
|
+
"description": "新的文件完整内容",
|
|
54
23
|
},
|
|
55
24
|
},
|
|
56
|
-
"required": ["
|
|
25
|
+
"required": ["file_path", "content"],
|
|
57
26
|
}
|
|
58
27
|
|
|
59
28
|
def __init__(self):
|
|
60
29
|
"""初始化文件重写工具"""
|
|
61
30
|
pass
|
|
62
31
|
|
|
63
|
-
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
64
|
-
"""
|
|
65
|
-
执行文件重写操作,完全替换文件内容
|
|
66
|
-
|
|
67
|
-
参数:
|
|
68
|
-
file (str): 文件路径
|
|
69
|
-
content (str): 新的文件内容
|
|
70
|
-
|
|
71
|
-
返回:
|
|
72
|
-
dict: 包含执行结果的字典
|
|
73
|
-
{
|
|
74
|
-
"success": bool, # 是否成功完成重写
|
|
75
|
-
"stdout": str, # 标准输出信息
|
|
76
|
-
"stderr": str # 错误信息
|
|
77
|
-
}
|
|
78
|
-
"""
|
|
79
|
-
import os
|
|
80
|
-
|
|
81
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
82
|
-
|
|
83
|
-
stdout_messages = []
|
|
84
|
-
stderr_messages = []
|
|
85
|
-
success = True
|
|
86
|
-
|
|
87
|
-
file_path = args["file"]
|
|
88
|
-
new_content = args["content"]
|
|
89
|
-
agent = args.get("agent", None)
|
|
90
|
-
abs_path = os.path.abspath(file_path)
|
|
91
|
-
|
|
92
|
-
# 创建已处理文件变量,用于失败时回滚
|
|
93
|
-
original_content = None
|
|
94
|
-
processed = False
|
|
95
|
-
|
|
32
|
+
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
33
|
+
"""执行文件重写操作"""
|
|
96
34
|
try:
|
|
97
|
-
|
|
35
|
+
file_path = args.get("file_path")
|
|
36
|
+
content = args.get("content")
|
|
37
|
+
|
|
38
|
+
if not file_path:
|
|
39
|
+
return {
|
|
40
|
+
"success": False,
|
|
41
|
+
"stdout": "",
|
|
42
|
+
"stderr": "缺少必需参数:file_path",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if content is None:
|
|
46
|
+
return {
|
|
47
|
+
"success": False,
|
|
48
|
+
"stdout": "",
|
|
49
|
+
"stderr": "缺少必需参数:content",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
abs_path = os.path.abspath(file_path)
|
|
53
|
+
original_content = None
|
|
54
|
+
processed = False
|
|
98
55
|
|
|
99
56
|
try:
|
|
100
|
-
|
|
57
|
+
file_exists = os.path.exists(abs_path)
|
|
101
58
|
if file_exists:
|
|
102
|
-
with open(abs_path, "r", encoding="utf-8") as
|
|
103
|
-
original_content =
|
|
59
|
+
with open(abs_path, "r", encoding="utf-8") as rf:
|
|
60
|
+
original_content = rf.read()
|
|
104
61
|
|
|
105
|
-
# 确保目录存在
|
|
106
62
|
os.makedirs(os.path.dirname(abs_path), exist_ok=True)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
with open(abs_path, "w", encoding="utf-8") as f:
|
|
110
|
-
f.write(new_content)
|
|
111
|
-
|
|
63
|
+
with open(abs_path, "w", encoding="utf-8") as wf:
|
|
64
|
+
wf.write(content)
|
|
112
65
|
processed = True
|
|
113
66
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
67
|
+
# 记录 REWRITE 操作调用统计
|
|
68
|
+
try:
|
|
69
|
+
from jarvis.jarvis_stats.stats import StatsManager
|
|
117
70
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
PrettyOutput.print(stderr_message, OutputType.WARNING)
|
|
122
|
-
success = False
|
|
71
|
+
StatsManager.increment("rewrite_file", group="tool")
|
|
72
|
+
except Exception:
|
|
73
|
+
pass
|
|
123
74
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
75
|
+
return {
|
|
76
|
+
"success": True,
|
|
77
|
+
"stdout": f"文件 {abs_path} 重写成功",
|
|
78
|
+
"stderr": "",
|
|
79
|
+
}
|
|
128
80
|
|
|
81
|
+
except Exception as e:
|
|
82
|
+
# 回滚已修改内容
|
|
129
83
|
try:
|
|
130
|
-
if
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
# 记录成功处理的文件(使用绝对路径)
|
|
148
|
-
if success and agent:
|
|
149
|
-
abs_path = os.path.abspath(file_path)
|
|
150
|
-
files = agent.get_user_data("files")
|
|
151
|
-
if files:
|
|
152
|
-
if abs_path not in files:
|
|
153
|
-
files.append(abs_path)
|
|
154
|
-
else:
|
|
155
|
-
files = [abs_path]
|
|
156
|
-
agent.set_user_data("files", files)
|
|
157
|
-
|
|
158
|
-
return {
|
|
159
|
-
"success": success,
|
|
160
|
-
"stdout": "\n".join(stdout_messages),
|
|
161
|
-
"stderr": "\n".join(stderr_messages),
|
|
162
|
-
}
|
|
84
|
+
if processed:
|
|
85
|
+
if original_content is None:
|
|
86
|
+
if os.path.exists(abs_path):
|
|
87
|
+
os.remove(abs_path)
|
|
88
|
+
else:
|
|
89
|
+
with open(abs_path, "w", encoding="utf-8") as wf:
|
|
90
|
+
wf.write(original_content)
|
|
91
|
+
except Exception:
|
|
92
|
+
pass
|
|
93
|
+
error_msg = f"文件重写失败: {str(e)}"
|
|
94
|
+
print(f"❌ {error_msg}")
|
|
95
|
+
return {
|
|
96
|
+
"success": False,
|
|
97
|
+
"stdout": "",
|
|
98
|
+
"stderr": error_msg,
|
|
99
|
+
}
|
|
163
100
|
|
|
164
101
|
except Exception as e:
|
|
165
|
-
error_msg = f"
|
|
166
|
-
|
|
102
|
+
error_msg = f"文件重写失败: {str(e)}"
|
|
103
|
+
print(f"❌ {error_msg}")
|
|
104
|
+
return {"success": False, "stdout": "", "stderr": error_msg}
|
|
167
105
|
|
|
168
|
-
# 如果有已修改的文件,尝试回滚
|
|
169
|
-
if processed:
|
|
170
|
-
rollback_message = "操作失败,正在回滚修改..."
|
|
171
|
-
stderr_messages.append(rollback_message)
|
|
172
|
-
|
|
173
|
-
try:
|
|
174
|
-
if original_content is None:
|
|
175
|
-
# 如果是新创建的文件,则删除
|
|
176
|
-
if os.path.exists(file_path):
|
|
177
|
-
os.remove(file_path)
|
|
178
|
-
stderr_messages.append(f"已删除新创建的文件: {file_path}")
|
|
179
|
-
else:
|
|
180
|
-
# 如果是修改的文件,则恢复原内容
|
|
181
|
-
with open(file_path, "w", encoding="utf-8") as f:
|
|
182
|
-
f.write(original_content)
|
|
183
|
-
stderr_messages.append(f"已回滚文件: {file_path}")
|
|
184
|
-
except:
|
|
185
|
-
stderr_messages.append(f"回滚文件失败: {file_path}")
|
|
186
|
-
|
|
187
|
-
return {
|
|
188
|
-
"success": False,
|
|
189
|
-
"stdout": "",
|
|
190
|
-
"stderr": error_msg + "\n" + "\n".join(stderr_messages),
|
|
191
|
-
}
|
|
@@ -6,7 +6,6 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Any, Dict
|
|
7
7
|
|
|
8
8
|
from jarvis.jarvis_utils.config import get_data_dir
|
|
9
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
10
9
|
from jarvis.jarvis_utils.globals import add_short_term_memory
|
|
11
10
|
|
|
12
11
|
|
|
@@ -14,18 +13,7 @@ class SaveMemoryTool:
|
|
|
14
13
|
"""保存记忆工具,用于将信息保存到长短期记忆系统"""
|
|
15
14
|
|
|
16
15
|
name = "save_memory"
|
|
17
|
-
description = ""
|
|
18
|
-
|
|
19
|
-
支持批量保存多条记忆,可以同时保存不同类型的记忆。
|
|
20
|
-
|
|
21
|
-
支持的记忆类型:
|
|
22
|
-
- project_long_term: 项目长期记忆(与当前项目相关的信息)
|
|
23
|
-
- global_long_term: 全局长期记忆(通用的信息、用户喜好、知识、方法等)
|
|
24
|
-
- short_term: 短期记忆(当前任务相关的信息)
|
|
25
|
-
|
|
26
|
-
项目长期记忆存储在当前目录的 .jarvis/memory 下
|
|
27
|
-
全局长期记忆和短期记忆存储在数据目录的 memory 子目录下
|
|
28
|
-
"""
|
|
16
|
+
description = "保存信息到长短期记忆系统。支持批量保存,记忆类型:project_long_term(项目长期)、global_long_term(全局长期)、short_term(短期)。"
|
|
29
17
|
|
|
30
18
|
parameters = {
|
|
31
19
|
"type": "object",
|
|
@@ -163,7 +151,7 @@ class SaveMemoryTool:
|
|
|
163
151
|
except Exception as e:
|
|
164
152
|
failed_count += 1
|
|
165
153
|
error_msg = f"保存第 {i+1} 条记忆失败: {str(e)}"
|
|
166
|
-
|
|
154
|
+
print(f"❌ {error_msg}")
|
|
167
155
|
results.append(
|
|
168
156
|
{
|
|
169
157
|
"error": error_msg,
|
|
@@ -190,5 +178,5 @@ class SaveMemoryTool:
|
|
|
190
178
|
|
|
191
179
|
except Exception as e:
|
|
192
180
|
error_msg = f"保存记忆失败: {str(e)}"
|
|
193
|
-
|
|
181
|
+
print(f"❌ {error_msg}")
|
|
194
182
|
return {"success": False, "stdout": "", "stderr": error_msg}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""网络搜索工具。"""
|
|
3
3
|
from typing import Any, Dict
|
|
4
4
|
|
|
5
|
-
import requests
|
|
5
|
+
import requests # type: ignore[import-untyped]
|
|
6
6
|
from markdownify import markdownify as md # type: ignore
|
|
7
7
|
|
|
8
8
|
# pylint: disable=import-error,missing-module-docstring
|
|
@@ -17,7 +17,6 @@ from jarvis.jarvis_utils.config import (
|
|
|
17
17
|
get_web_search_model_name,
|
|
18
18
|
)
|
|
19
19
|
from jarvis.jarvis_utils.http import get as http_get
|
|
20
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
21
20
|
|
|
22
21
|
|
|
23
22
|
class SearchWebTool:
|
|
@@ -65,12 +64,9 @@ class SearchWebTool:
|
|
|
65
64
|
visited_urls.append(url)
|
|
66
65
|
visited_count += 1
|
|
67
66
|
except requests.exceptions.HTTPError as e:
|
|
68
|
-
|
|
69
|
-
f"⚠️ HTTP错误 {e.response.status_code} 访问 {url}",
|
|
70
|
-
OutputType.WARNING,
|
|
71
|
-
)
|
|
67
|
+
print(f"⚠️ HTTP错误 {e.response.status_code} 访问 {url}")
|
|
72
68
|
except requests.exceptions.RequestException as e:
|
|
73
|
-
|
|
69
|
+
print(f"⚠️ 请求错误: {e}")
|
|
74
70
|
|
|
75
71
|
if not full_content.strip():
|
|
76
72
|
return {
|
|
@@ -108,7 +104,7 @@ class SearchWebTool:
|
|
|
108
104
|
return {"stdout": summary, "stderr": "", "success": True}
|
|
109
105
|
|
|
110
106
|
except Exception as e:
|
|
111
|
-
|
|
107
|
+
print(f"❌ 网页搜索过程中发生错误: {e}")
|
|
112
108
|
return {
|
|
113
109
|
"stdout": "",
|
|
114
110
|
"stderr": f"网页搜索过程中发生错误: {e}",
|
|
@@ -147,11 +143,13 @@ class SearchWebTool:
|
|
|
147
143
|
if model.support_web():
|
|
148
144
|
model.set_web(True)
|
|
149
145
|
model.set_suppress_output(False)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
146
|
+
response = model.chat_until_success(query)
|
|
147
|
+
if response and response.strip():
|
|
148
|
+
return {
|
|
149
|
+
"stdout": response,
|
|
150
|
+
"stderr": "",
|
|
151
|
+
"success": True,
|
|
152
|
+
}
|
|
155
153
|
|
|
156
154
|
# 否则使用现有的模型选择流程
|
|
157
155
|
if agent.model.support_web():
|
|
@@ -161,11 +159,13 @@ class SearchWebTool:
|
|
|
161
159
|
model.set_model_name(agent.model.name())
|
|
162
160
|
model.set_web(True)
|
|
163
161
|
model.set_suppress_output(False)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
response = model.chat_until_success(query)
|
|
163
|
+
if response and response.strip():
|
|
164
|
+
return {
|
|
165
|
+
"stdout": response,
|
|
166
|
+
"stderr": "",
|
|
167
|
+
"success": True,
|
|
168
|
+
}
|
|
169
169
|
|
|
170
170
|
return self._search_with_ddgs(query, agent)
|
|
171
171
|
|
jarvis/jarvis_tools/sub_agent.py
CHANGED
|
@@ -4,17 +4,17 @@ sub_agent 工具
|
|
|
4
4
|
将子任务交给通用 Agent 执行,并返回执行结果。
|
|
5
5
|
|
|
6
6
|
约定:
|
|
7
|
-
- 必填参数:task, name,
|
|
8
|
-
-
|
|
7
|
+
- 必填参数:task, name, system_prompt, summary_prompt
|
|
8
|
+
- 可选参数:background
|
|
9
|
+
- 工具集:默认使用系统工具集(无需传入 use_tools)
|
|
10
|
+
- 继承父 Agent 的部分配置:model_group、input_handler、execute_tool_confirm、multiline_inputer、non_interactive、use_methodology、use_analysis;其他参数需显式提供
|
|
9
11
|
- 子Agent必须自动完成(auto_complete=True)且需要summary(need_summary=True)
|
|
10
12
|
"""
|
|
11
|
-
from typing import Any, Dict
|
|
13
|
+
from typing import Any, Dict
|
|
12
14
|
import json
|
|
13
15
|
|
|
14
16
|
from jarvis.jarvis_agent import Agent
|
|
15
17
|
from jarvis.jarvis_utils.globals import delete_agent
|
|
16
|
-
from jarvis.jarvis_tools.registry import ToolRegistry
|
|
17
|
-
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class SubAgentTool:
|
|
@@ -27,7 +27,7 @@ class SubAgentTool:
|
|
|
27
27
|
|
|
28
28
|
# 必须与文件名一致,供 ToolRegistry 自动注册
|
|
29
29
|
name = "sub_agent"
|
|
30
|
-
description = "将子任务交给通用 Agent
|
|
30
|
+
description = "将子任务交给通用 Agent 执行并返回结果(继承父Agent部分配置,自动完成并生成总结)。"
|
|
31
31
|
parameters = {
|
|
32
32
|
"type": "object",
|
|
33
33
|
"properties": {
|
|
@@ -41,7 +41,7 @@ class SubAgentTool:
|
|
|
41
41
|
},
|
|
42
42
|
"background": {
|
|
43
43
|
"type": "string",
|
|
44
|
-
"description": "
|
|
44
|
+
"description": "任务背景与已知信息(可选,将与任务一并提供给子Agent)",
|
|
45
45
|
},
|
|
46
46
|
"system_prompt": {
|
|
47
47
|
"type": "string",
|
|
@@ -51,25 +51,16 @@ class SubAgentTool:
|
|
|
51
51
|
"type": "string",
|
|
52
52
|
"description": "覆盖子Agent的总结提示词(必填)",
|
|
53
53
|
},
|
|
54
|
-
"
|
|
55
|
-
"type": "
|
|
56
|
-
"
|
|
57
|
-
"description": "限制子Agent可用的工具名称列表(必填)。兼容以逗号分隔的字符串输入。可用的工具列表:"
|
|
58
|
-
+ "\n".join(
|
|
59
|
-
[
|
|
60
|
-
t["name"] + ": " + t["description"]
|
|
61
|
-
for t in ToolRegistry().get_all_tools()
|
|
62
|
-
]
|
|
63
|
-
),
|
|
54
|
+
"non_interactive": {
|
|
55
|
+
"type": "boolean",
|
|
56
|
+
"description": "是否启用无交互模式(可选,默认继承父Agent或系统默认)",
|
|
64
57
|
},
|
|
65
58
|
},
|
|
66
59
|
"required": [
|
|
67
60
|
"task",
|
|
68
61
|
"name",
|
|
69
|
-
"background",
|
|
70
62
|
"system_prompt",
|
|
71
63
|
"summary_prompt",
|
|
72
|
-
"use_tools",
|
|
73
64
|
],
|
|
74
65
|
}
|
|
75
66
|
|
|
@@ -105,16 +96,6 @@ class SubAgentTool:
|
|
|
105
96
|
summary_prompt = str(args.get("summary_prompt", "")).strip()
|
|
106
97
|
agent_name = str(args.get("name", "")).strip()
|
|
107
98
|
|
|
108
|
-
# 解析可用工具列表(支持数组或以逗号分隔的字符串)
|
|
109
|
-
_use_tools = args.get("use_tools", None)
|
|
110
|
-
use_tools: List[str] = []
|
|
111
|
-
if isinstance(_use_tools, list):
|
|
112
|
-
use_tools = [str(x).strip() for x in _use_tools if str(x).strip()]
|
|
113
|
-
elif isinstance(_use_tools, str):
|
|
114
|
-
use_tools = [s.strip() for s in _use_tools.split(",") if s.strip()]
|
|
115
|
-
else:
|
|
116
|
-
use_tools = []
|
|
117
|
-
|
|
118
99
|
errors = []
|
|
119
100
|
if not system_prompt:
|
|
120
101
|
errors.append("system_prompt 不能为空")
|
|
@@ -122,8 +103,6 @@ class SubAgentTool:
|
|
|
122
103
|
errors.append("summary_prompt 不能为空")
|
|
123
104
|
if not agent_name:
|
|
124
105
|
errors.append("name 不能为空")
|
|
125
|
-
if not use_tools:
|
|
126
|
-
errors.append("use_tools 不能为空")
|
|
127
106
|
if not background:
|
|
128
107
|
errors.append("background 不能为空")
|
|
129
108
|
|
|
@@ -137,20 +116,29 @@ class SubAgentTool:
|
|
|
137
116
|
# 基于父Agent(如有)继承部分配置后创建子Agent
|
|
138
117
|
parent_agent = args.get("agent", None)
|
|
139
118
|
parent_model_group = None
|
|
140
|
-
parent_input_handler = None
|
|
141
119
|
parent_execute_tool_confirm = None
|
|
142
120
|
parent_multiline_inputer = None
|
|
121
|
+
parent_non_interactive = None
|
|
122
|
+
parent_use_methodology = None
|
|
123
|
+
parent_use_analysis = None
|
|
143
124
|
try:
|
|
144
125
|
if parent_agent is not None:
|
|
145
126
|
if getattr(parent_agent, "model", None):
|
|
146
127
|
parent_model_group = getattr(parent_agent.model, "model_group", None)
|
|
147
|
-
parent_input_handler = getattr(parent_agent, "input_handler", None)
|
|
148
128
|
parent_execute_tool_confirm = getattr(parent_agent, "execute_tool_confirm", None)
|
|
149
129
|
parent_multiline_inputer = getattr(parent_agent, "multiline_inputer", None)
|
|
130
|
+
parent_non_interactive = getattr(parent_agent, "non_interactive", None)
|
|
131
|
+
parent_use_methodology = getattr(parent_agent, "use_methodology", None)
|
|
132
|
+
parent_use_analysis = getattr(parent_agent, "use_analysis", None)
|
|
150
133
|
except Exception:
|
|
151
134
|
# 安全兜底:无法从父Agent获取配置则保持为None,使用系统默认
|
|
152
135
|
pass
|
|
153
136
|
|
|
137
|
+
# 可选参数:允许显式覆盖无交互模式
|
|
138
|
+
explicit_non_interactive = args.get("non_interactive", None)
|
|
139
|
+
if explicit_non_interactive is not None:
|
|
140
|
+
parent_non_interactive = bool(explicit_non_interactive)
|
|
141
|
+
|
|
154
142
|
agent = Agent(
|
|
155
143
|
system_prompt=system_prompt,
|
|
156
144
|
name=agent_name,
|
|
@@ -158,22 +146,30 @@ class SubAgentTool:
|
|
|
158
146
|
model_group=parent_model_group,
|
|
159
147
|
summary_prompt=summary_prompt,
|
|
160
148
|
auto_complete=auto_complete,
|
|
161
|
-
output_handler=None,
|
|
162
149
|
use_tools=None,
|
|
163
|
-
input_handler=parent_input_handler,
|
|
164
150
|
execute_tool_confirm=parent_execute_tool_confirm,
|
|
165
151
|
need_summary=need_summary,
|
|
166
152
|
multiline_inputer=parent_multiline_inputer,
|
|
167
|
-
use_methodology=
|
|
168
|
-
use_analysis=
|
|
153
|
+
use_methodology=parent_use_methodology,
|
|
154
|
+
use_analysis=parent_use_analysis,
|
|
169
155
|
force_save_memory=None,
|
|
170
156
|
files=None,
|
|
157
|
+
non_interactive=parent_non_interactive,
|
|
171
158
|
)
|
|
172
159
|
|
|
173
|
-
#
|
|
160
|
+
# 禁用 sub_agent 和 sub_code_agent,避免无限递归
|
|
174
161
|
try:
|
|
175
|
-
|
|
162
|
+
# 获取当前启用的工具列表
|
|
163
|
+
tool_registry = agent.get_tool_registry()
|
|
164
|
+
if tool_registry:
|
|
165
|
+
current_tools = [t.get("name") for t in tool_registry.get_all_tools() if isinstance(t, dict) and t.get("name")]
|
|
166
|
+
# 过滤掉禁止的工具
|
|
167
|
+
forbidden_tools = {"sub_agent", "sub_code_agent"}
|
|
168
|
+
filtered_tools = [t for t in current_tools if t not in forbidden_tools]
|
|
169
|
+
if filtered_tools:
|
|
170
|
+
agent.set_use_tools(filtered_tools)
|
|
176
171
|
except Exception:
|
|
172
|
+
# 如果禁用工具失败,不影响主流程
|
|
177
173
|
pass
|
|
178
174
|
|
|
179
175
|
# 校验子Agent所用模型是否有效,必要时回退到平台可用模型
|
|
@@ -185,10 +181,7 @@ class SubAgentTool:
|
|
|
185
181
|
available_names = [m for m, _ in available_models]
|
|
186
182
|
current_model_name = platform.name()
|
|
187
183
|
if current_model_name not in available_names:
|
|
188
|
-
|
|
189
|
-
f"检测到子Agent模型 {current_model_name} 不存在于平台 {platform.platform_name()} 的可用模型列表,将回退到 {available_names[0]}",
|
|
190
|
-
OutputType.WARNING,
|
|
191
|
-
)
|
|
184
|
+
print(f"⚠️ 检测到子Agent模型 {current_model_name} 不存在于平台 {platform.platform_name()} 的可用模型列表,将回退到 {available_names[0]}")
|
|
192
185
|
platform.set_model_name(available_names[0])
|
|
193
186
|
except Exception:
|
|
194
187
|
# 获取模型列表或设置模型失败时,保持原设置并继续,交由底层报错处理
|