jarvis-ai-assistant 0.2.7__py3-none-any.whl → 0.3.0__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 +267 -240
- jarvis/jarvis_agent/agent_manager.py +85 -0
- jarvis/jarvis_agent/config_editor.py +53 -0
- jarvis/jarvis_agent/file_methodology_manager.py +105 -0
- jarvis/jarvis_agent/jarvis.py +37 -398
- jarvis/jarvis_agent/memory_manager.py +133 -0
- jarvis/jarvis_agent/methodology_share_manager.py +174 -0
- jarvis/jarvis_agent/prompts.py +18 -3
- jarvis/jarvis_agent/share_manager.py +176 -0
- jarvis/jarvis_agent/task_analyzer.py +126 -0
- jarvis/jarvis_agent/task_manager.py +111 -0
- jarvis/jarvis_agent/tool_share_manager.py +139 -0
- jarvis/jarvis_code_agent/code_agent.py +26 -20
- jarvis/jarvis_data/config_schema.json +37 -0
- jarvis/jarvis_platform/ai8.py +13 -1
- jarvis/jarvis_platform/base.py +20 -5
- jarvis/jarvis_platform/human.py +11 -1
- jarvis/jarvis_platform/kimi.py +10 -0
- jarvis/jarvis_platform/openai.py +20 -0
- jarvis/jarvis_platform/tongyi.py +14 -9
- jarvis/jarvis_platform/yuanbao.py +10 -0
- jarvis/jarvis_platform_manager/main.py +12 -12
- jarvis/jarvis_tools/registry.py +79 -20
- jarvis/jarvis_tools/retrieve_memory.py +36 -8
- jarvis/jarvis_utils/clipboard.py +90 -0
- jarvis/jarvis_utils/config.py +64 -0
- jarvis/jarvis_utils/git_utils.py +17 -7
- jarvis/jarvis_utils/globals.py +18 -12
- jarvis/jarvis_utils/input.py +118 -16
- jarvis/jarvis_utils/methodology.py +48 -5
- jarvis/jarvis_utils/utils.py +196 -106
- {jarvis_ai_assistant-0.2.7.dist-info → jarvis_ai_assistant-0.3.0.dist-info}/METADATA +1 -1
- {jarvis_ai_assistant-0.2.7.dist-info → jarvis_ai_assistant-0.3.0.dist-info}/RECORD +38 -28
- {jarvis_ai_assistant-0.2.7.dist-info → jarvis_ai_assistant-0.3.0.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.2.7.dist-info → jarvis_ai_assistant-0.3.0.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.2.7.dist-info → jarvis_ai_assistant-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.2.7.dist-info → jarvis_ai_assistant-0.3.0.dist-info}/top_level.txt +0 -0
jarvis/jarvis_tools/registry.py
CHANGED
@@ -107,17 +107,13 @@ arguments:
|
|
107
107
|
|
108
108
|
|
109
109
|
class OutputHandlerProtocol(Protocol):
|
110
|
-
def name(self) -> str:
|
111
|
-
...
|
110
|
+
def name(self) -> str: ...
|
112
111
|
|
113
|
-
def can_handle(self, response: str) -> bool:
|
114
|
-
...
|
112
|
+
def can_handle(self, response: str) -> bool: ...
|
115
113
|
|
116
|
-
def prompt(self) -> str:
|
117
|
-
...
|
114
|
+
def prompt(self) -> str: ...
|
118
115
|
|
119
|
-
def handle(self, response: str, agent: Any) -> Tuple[bool, Any]:
|
120
|
-
...
|
116
|
+
def handle(self, response: str, agent: Any) -> Tuple[bool, Any]: ...
|
121
117
|
|
122
118
|
|
123
119
|
class ToolRegistry(OutputHandlerProtocol):
|
@@ -138,9 +134,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
138
134
|
try:
|
139
135
|
tools_prompt += " <tool>\n"
|
140
136
|
tools_prompt += f" <name>名称: {tool['name']}</name>\n"
|
141
|
-
tools_prompt +=
|
142
|
-
f" <description>描述: {tool['description']}</description>\n"
|
143
|
-
)
|
137
|
+
tools_prompt += f" <description>描述: {tool['description']}</description>\n"
|
144
138
|
tools_prompt += " <parameters>\n"
|
145
139
|
tools_prompt += " <yaml>|\n"
|
146
140
|
|
@@ -197,20 +191,22 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
197
191
|
self._load_builtin_tools()
|
198
192
|
self._load_external_tools()
|
199
193
|
self._load_mcp_tools()
|
194
|
+
# 应用工具配置组过滤
|
195
|
+
self._apply_tool_config_filter()
|
200
196
|
|
201
197
|
def _get_tool_stats(self) -> Dict[str, int]:
|
202
198
|
"""从数据目录获取工具调用统计"""
|
203
199
|
from jarvis.jarvis_stats.stats import StatsManager
|
204
200
|
from datetime import datetime, timedelta
|
205
|
-
|
201
|
+
|
206
202
|
# 获取所有工具的统计数据
|
207
203
|
tool_stats = {}
|
208
204
|
tools = self.get_all_tools()
|
209
|
-
|
205
|
+
|
210
206
|
# 获取所有历史数据(从很早的时间开始)
|
211
207
|
end_time = datetime.now()
|
212
208
|
start_time = datetime(2000, 1, 1) # 使用一个足够早的时间
|
213
|
-
|
209
|
+
|
214
210
|
for tool in tools:
|
215
211
|
tool_name = tool["name"]
|
216
212
|
# 获取该工具的统计数据
|
@@ -218,22 +214,22 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
218
214
|
metric_name=tool_name,
|
219
215
|
start_time=start_time,
|
220
216
|
end_time=end_time,
|
221
|
-
tags={"group": "tool"}
|
217
|
+
tags={"group": "tool"},
|
222
218
|
)
|
223
|
-
|
219
|
+
|
224
220
|
# 计算总调用次数
|
225
221
|
if stats_data and "records" in stats_data:
|
226
222
|
total_count = sum(record["value"] for record in stats_data["records"])
|
227
223
|
tool_stats[tool_name] = int(total_count)
|
228
224
|
else:
|
229
225
|
tool_stats[tool_name] = 0
|
230
|
-
|
226
|
+
|
231
227
|
return tool_stats
|
232
228
|
|
233
229
|
def _update_tool_stats(self, name: str) -> None:
|
234
230
|
"""更新工具调用统计"""
|
235
231
|
from jarvis.jarvis_stats.stats import StatsManager
|
236
|
-
|
232
|
+
|
237
233
|
StatsManager.increment(name, group="tool")
|
238
234
|
|
239
235
|
def use_tools(self, name: List[str]) -> None:
|
@@ -264,6 +260,36 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
264
260
|
name: tool for name, tool in self.tools.items() if name not in names
|
265
261
|
}
|
266
262
|
|
263
|
+
def _apply_tool_config_filter(self) -> None:
|
264
|
+
"""应用工具配置组的过滤规则"""
|
265
|
+
from jarvis.jarvis_utils.config import get_tool_use_list, get_tool_dont_use_list
|
266
|
+
|
267
|
+
use_list = get_tool_use_list()
|
268
|
+
dont_use_list = get_tool_dont_use_list()
|
269
|
+
|
270
|
+
# 如果配置了 use 列表,只保留列表中的工具
|
271
|
+
if use_list:
|
272
|
+
filtered_tools = {}
|
273
|
+
for tool_name in use_list:
|
274
|
+
if tool_name in self.tools:
|
275
|
+
filtered_tools[tool_name] = self.tools[tool_name]
|
276
|
+
else:
|
277
|
+
PrettyOutput.print(
|
278
|
+
f"警告: 配置的工具 '{tool_name}' 不存在",
|
279
|
+
OutputType.WARNING,
|
280
|
+
)
|
281
|
+
self.tools = filtered_tools
|
282
|
+
|
283
|
+
# 如果配置了 dont_use 列表,排除列表中的工具
|
284
|
+
if dont_use_list:
|
285
|
+
for tool_name in dont_use_list:
|
286
|
+
if tool_name in self.tools:
|
287
|
+
del self.tools[tool_name]
|
288
|
+
PrettyOutput.print(
|
289
|
+
f"已排除工具: {tool_name}",
|
290
|
+
OutputType.INFO,
|
291
|
+
)
|
292
|
+
|
267
293
|
def _load_mcp_tools(self) -> None:
|
268
294
|
"""加载MCP工具,优先从配置获取,其次从目录扫描"""
|
269
295
|
from jarvis.jarvis_utils.config import get_mcp_config
|
@@ -292,7 +318,9 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
292
318
|
config = yaml.safe_load(open(file_path, "r", encoding="utf-8"))
|
293
319
|
self.register_mcp_tool_by_config(config)
|
294
320
|
except Exception as e:
|
295
|
-
PrettyOutput.print(
|
321
|
+
PrettyOutput.print(
|
322
|
+
f"文件 {file_path} 加载失败: {str(e)}", OutputType.WARNING
|
323
|
+
)
|
296
324
|
|
297
325
|
def _load_builtin_tools(self) -> None:
|
298
326
|
"""从内置工具目录加载工具"""
|
@@ -308,8 +336,33 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
308
336
|
|
309
337
|
def _load_external_tools(self) -> None:
|
310
338
|
"""从jarvis_data/tools和配置的目录加载外部工具"""
|
339
|
+
from jarvis.jarvis_utils.config import get_central_tool_repo
|
340
|
+
|
311
341
|
tool_dirs = [str(Path(get_data_dir()) / "tools")] + get_tool_load_dirs()
|
312
342
|
|
343
|
+
# 如果配置了中心工具仓库,将其添加到加载路径
|
344
|
+
central_repo = get_central_tool_repo()
|
345
|
+
if central_repo:
|
346
|
+
# 中心工具仓库存储在数据目录下的特定位置
|
347
|
+
central_repo_path = os.path.join(get_data_dir(), "central_tool_repo")
|
348
|
+
tool_dirs.append(central_repo_path)
|
349
|
+
|
350
|
+
# 确保中心工具仓库被克隆/更新
|
351
|
+
if not os.path.exists(central_repo_path):
|
352
|
+
try:
|
353
|
+
import subprocess
|
354
|
+
|
355
|
+
PrettyOutput.print(
|
356
|
+
f"正在克隆中心工具仓库: {central_repo}", OutputType.INFO
|
357
|
+
)
|
358
|
+
subprocess.run(
|
359
|
+
["git", "clone", central_repo, central_repo_path], check=True
|
360
|
+
)
|
361
|
+
except Exception as e:
|
362
|
+
PrettyOutput.print(
|
363
|
+
f"克隆中心工具仓库失败: {str(e)}", OutputType.ERROR
|
364
|
+
)
|
365
|
+
|
313
366
|
# --- 全局每日更新检查 ---
|
314
367
|
daily_check_git_updates(tool_dirs, "tools")
|
315
368
|
|
@@ -662,6 +715,10 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
662
715
|
parameters: 工具参数定义
|
663
716
|
func: 工具执行函数
|
664
717
|
"""
|
718
|
+
if name in self.tools:
|
719
|
+
PrettyOutput.print(
|
720
|
+
f"警告: 工具 '{name}' 已存在,将被覆盖", OutputType.WARNING
|
721
|
+
)
|
665
722
|
self.tools[name] = Tool(name, description, parameters, func)
|
666
723
|
|
667
724
|
def get_tool(self, name: str) -> Optional[Tool]:
|
@@ -735,7 +792,9 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
735
792
|
"""
|
736
793
|
if len(output.splitlines()) > 60:
|
737
794
|
lines = output.splitlines()
|
738
|
-
return "\n".join(
|
795
|
+
return "\n".join(
|
796
|
+
lines[:30] + ["\n...内容太长,已截取前后30行...\n"] + lines[-30:]
|
797
|
+
)
|
739
798
|
return output
|
740
799
|
|
741
800
|
def handle_tool_calls(self, tool_call: Dict[str, Any], agent: Any) -> str:
|
@@ -4,9 +4,10 @@ import random
|
|
4
4
|
from pathlib import Path
|
5
5
|
from typing import Any, Dict, List, Optional
|
6
6
|
|
7
|
-
from jarvis.jarvis_utils.config import get_data_dir
|
7
|
+
from jarvis.jarvis_utils.config import get_data_dir, get_max_input_token_count
|
8
8
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
9
9
|
from jarvis.jarvis_utils.globals import get_short_term_memories
|
10
|
+
from jarvis.jarvis_utils.embedding import get_context_token_count
|
10
11
|
|
11
12
|
|
12
13
|
class RetrieveMemoryTool:
|
@@ -131,14 +132,41 @@ class RetrieveMemoryTool:
|
|
131
132
|
# 按创建时间排序(最新的在前)
|
132
133
|
all_memories.sort(key=lambda x: x.get("created_at", ""), reverse=True)
|
133
134
|
|
134
|
-
#
|
135
|
-
|
136
|
-
|
137
|
-
# 重新排序,保持时间顺序
|
138
|
-
all_memories.sort(key=lambda x: x.get("created_at", ""), reverse=True)
|
135
|
+
# 获取最大输入token数的2/3作为记忆的token限制
|
136
|
+
max_input_tokens = get_max_input_token_count()
|
137
|
+
memory_token_limit = int(max_input_tokens * 2 / 3)
|
139
138
|
|
140
|
-
#
|
141
|
-
|
139
|
+
# 基于token限制和条数限制筛选记忆
|
140
|
+
filtered_memories: List[Dict[str, Any]] = []
|
141
|
+
total_tokens = 0
|
142
|
+
|
143
|
+
for memory in all_memories:
|
144
|
+
# 计算当前记忆的token数量
|
145
|
+
memory_content = json.dumps(memory, ensure_ascii=False)
|
146
|
+
memory_tokens = get_context_token_count(memory_content)
|
147
|
+
|
148
|
+
# 检查是否超过token限制
|
149
|
+
if total_tokens + memory_tokens > memory_token_limit:
|
150
|
+
PrettyOutput.print(
|
151
|
+
f"达到token限制 ({total_tokens}/{memory_token_limit}),停止加载更多记忆",
|
152
|
+
OutputType.INFO,
|
153
|
+
)
|
154
|
+
break
|
155
|
+
|
156
|
+
# 检查是否超过50条限制
|
157
|
+
if len(filtered_memories) >= 50:
|
158
|
+
PrettyOutput.print(
|
159
|
+
f"达到记忆条数限制 (50条),停止加载更多记忆", OutputType.INFO
|
160
|
+
)
|
161
|
+
break
|
162
|
+
|
163
|
+
filtered_memories.append(memory)
|
164
|
+
total_tokens += memory_tokens
|
165
|
+
|
166
|
+
all_memories = filtered_memories
|
167
|
+
|
168
|
+
# 如果指定了额外的限制,只返回前N个
|
169
|
+
if limit and len(all_memories) > limit:
|
142
170
|
all_memories = all_memories[:limit]
|
143
171
|
|
144
172
|
# 打印结果摘要
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
import platform
|
3
|
+
import subprocess
|
4
|
+
|
5
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
6
|
+
|
7
|
+
|
8
|
+
def copy_to_clipboard(text: str) -> None:
|
9
|
+
"""将文本复制到剪贴板,支持Windows、macOS和Linux
|
10
|
+
|
11
|
+
参数:
|
12
|
+
text: 要复制的文本
|
13
|
+
"""
|
14
|
+
print("--- 剪贴板内容开始 ---")
|
15
|
+
print(text)
|
16
|
+
print("--- 剪贴板内容结束 ---")
|
17
|
+
|
18
|
+
system = platform.system()
|
19
|
+
|
20
|
+
# Windows系统
|
21
|
+
if system == "Windows":
|
22
|
+
try:
|
23
|
+
# 使用Windows的clip命令
|
24
|
+
process = subprocess.Popen(
|
25
|
+
["clip"],
|
26
|
+
stdin=subprocess.PIPE,
|
27
|
+
stdout=subprocess.DEVNULL,
|
28
|
+
stderr=subprocess.DEVNULL,
|
29
|
+
shell=True,
|
30
|
+
)
|
31
|
+
if process.stdin:
|
32
|
+
process.stdin.write(text.encode("utf-8"))
|
33
|
+
process.stdin.close()
|
34
|
+
return
|
35
|
+
except Exception as e:
|
36
|
+
PrettyOutput.print(f"使用Windows clip命令时出错: {e}", OutputType.WARNING)
|
37
|
+
|
38
|
+
# macOS系统
|
39
|
+
elif system == "Darwin":
|
40
|
+
try:
|
41
|
+
process = subprocess.Popen(
|
42
|
+
["pbcopy"],
|
43
|
+
stdin=subprocess.PIPE,
|
44
|
+
stdout=subprocess.DEVNULL,
|
45
|
+
stderr=subprocess.DEVNULL,
|
46
|
+
)
|
47
|
+
if process.stdin:
|
48
|
+
process.stdin.write(text.encode("utf-8"))
|
49
|
+
process.stdin.close()
|
50
|
+
return
|
51
|
+
except Exception as e:
|
52
|
+
PrettyOutput.print(f"使用macOS pbcopy命令时出错: {e}", OutputType.WARNING)
|
53
|
+
|
54
|
+
# Linux系统
|
55
|
+
else:
|
56
|
+
# 尝试使用 xsel
|
57
|
+
try:
|
58
|
+
process = subprocess.Popen(
|
59
|
+
["xsel", "-b", "-i"],
|
60
|
+
stdin=subprocess.PIPE,
|
61
|
+
stdout=subprocess.DEVNULL,
|
62
|
+
stderr=subprocess.DEVNULL,
|
63
|
+
)
|
64
|
+
if process.stdin:
|
65
|
+
process.stdin.write(text.encode("utf-8"))
|
66
|
+
process.stdin.close()
|
67
|
+
return
|
68
|
+
except FileNotFoundError:
|
69
|
+
pass # xsel 未安装,继续尝试下一个
|
70
|
+
except Exception as e:
|
71
|
+
PrettyOutput.print(f"使用xsel时出错: {e}", OutputType.WARNING)
|
72
|
+
|
73
|
+
# 尝试使用 xclip
|
74
|
+
try:
|
75
|
+
process = subprocess.Popen(
|
76
|
+
["xclip", "-selection", "clipboard"],
|
77
|
+
stdin=subprocess.PIPE,
|
78
|
+
stdout=subprocess.DEVNULL,
|
79
|
+
stderr=subprocess.DEVNULL,
|
80
|
+
)
|
81
|
+
if process.stdin:
|
82
|
+
process.stdin.write(text.encode("utf-8"))
|
83
|
+
process.stdin.close()
|
84
|
+
return
|
85
|
+
except FileNotFoundError:
|
86
|
+
PrettyOutput.print(
|
87
|
+
"xsel 和 xclip 均未安装, 无法复制到剪贴板", OutputType.WARNING
|
88
|
+
)
|
89
|
+
except Exception as e:
|
90
|
+
PrettyOutput.print(f"使用xclip时出错: {e}", OutputType.WARNING)
|
jarvis/jarvis_utils/config.py
CHANGED
@@ -319,6 +319,16 @@ def get_central_methodology_repo() -> str:
|
|
319
319
|
return GLOBAL_CONFIG_DATA.get("JARVIS_CENTRAL_METHODOLOGY_REPO", "")
|
320
320
|
|
321
321
|
|
322
|
+
def get_central_tool_repo() -> str:
|
323
|
+
"""
|
324
|
+
获取中心工具Git仓库地址。
|
325
|
+
|
326
|
+
返回:
|
327
|
+
str: 中心工具Git仓库地址,如果未配置则返回空字符串
|
328
|
+
"""
|
329
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_CENTRAL_TOOL_REPO", "")
|
330
|
+
|
331
|
+
|
322
332
|
def is_print_prompt() -> bool:
|
323
333
|
"""
|
324
334
|
获取是否打印提示。
|
@@ -477,3 +487,57 @@ def get_rag_use_rerank() -> bool:
|
|
477
487
|
"""
|
478
488
|
config = _get_resolved_rag_config()
|
479
489
|
return config.get("use_rerank", True) is True
|
490
|
+
|
491
|
+
|
492
|
+
# ==============================================================================
|
493
|
+
# Tool Configuration
|
494
|
+
# ==============================================================================
|
495
|
+
|
496
|
+
|
497
|
+
def _get_resolved_tool_config(
|
498
|
+
tool_group_override: Optional[str] = None,
|
499
|
+
) -> Dict[str, Any]:
|
500
|
+
"""
|
501
|
+
解析并合并工具配置,处理工具组。
|
502
|
+
|
503
|
+
优先级顺序:
|
504
|
+
1. JARVIS_TOOL_GROUP 中定义的组配置
|
505
|
+
2. 默认配置(所有工具都启用)
|
506
|
+
|
507
|
+
返回:
|
508
|
+
Dict[str, Any]: 解析后的工具配置字典,包含 'use' 和 'dont_use' 列表
|
509
|
+
"""
|
510
|
+
group_config = {}
|
511
|
+
tool_group_name = tool_group_override or GLOBAL_CONFIG_DATA.get("JARVIS_TOOL_GROUP")
|
512
|
+
tool_groups = GLOBAL_CONFIG_DATA.get("JARVIS_TOOL_GROUPS", [])
|
513
|
+
|
514
|
+
if tool_group_name and isinstance(tool_groups, list):
|
515
|
+
for group_item in tool_groups:
|
516
|
+
if isinstance(group_item, dict) and tool_group_name in group_item:
|
517
|
+
group_config = group_item[tool_group_name]
|
518
|
+
break
|
519
|
+
|
520
|
+
# 如果没有找到配置组,返回默认配置(空列表表示使用所有工具)
|
521
|
+
return group_config.copy() if group_config else {"use": [], "dont_use": []}
|
522
|
+
|
523
|
+
|
524
|
+
def get_tool_use_list() -> List[str]:
|
525
|
+
"""
|
526
|
+
获取要使用的工具列表。
|
527
|
+
|
528
|
+
返回:
|
529
|
+
List[str]: 要使用的工具名称列表,空列表表示使用所有工具
|
530
|
+
"""
|
531
|
+
config = _get_resolved_tool_config()
|
532
|
+
return config.get("use", [])
|
533
|
+
|
534
|
+
|
535
|
+
def get_tool_dont_use_list() -> List[str]:
|
536
|
+
"""
|
537
|
+
获取不使用的工具列表。
|
538
|
+
|
539
|
+
返回:
|
540
|
+
List[str]: 不使用的工具名称列表
|
541
|
+
"""
|
542
|
+
config = _get_resolved_tool_config()
|
543
|
+
return config.get("dont_use", [])
|
jarvis/jarvis_utils/git_utils.py
CHANGED
@@ -214,7 +214,9 @@ def handle_commit_workflow() -> bool:
|
|
214
214
|
Returns:
|
215
215
|
bool: 提交是否成功
|
216
216
|
"""
|
217
|
-
if is_confirm_before_apply_patch() and not user_confirm(
|
217
|
+
if is_confirm_before_apply_patch() and not user_confirm(
|
218
|
+
"是否要提交代码?", default=True
|
219
|
+
):
|
218
220
|
revert_change()
|
219
221
|
return False
|
220
222
|
|
@@ -280,7 +282,7 @@ def get_latest_commit_hash() -> str:
|
|
280
282
|
return ""
|
281
283
|
|
282
284
|
|
283
|
-
def get_modified_line_ranges() -> Dict[str, Tuple[int, int]]:
|
285
|
+
def get_modified_line_ranges() -> Dict[str, List[Tuple[int, int]]]:
|
284
286
|
"""从Git差异中获取所有更改文件的修改行范围
|
285
287
|
|
286
288
|
返回:
|
@@ -291,7 +293,7 @@ def get_modified_line_ranges() -> Dict[str, Tuple[int, int]]:
|
|
291
293
|
diff_output = os.popen("git show").read()
|
292
294
|
|
293
295
|
# 解析差异以获取修改的文件及其行范围
|
294
|
-
result = {}
|
296
|
+
result: Dict[str, List[Tuple[int, int]]] = {}
|
295
297
|
current_file = None
|
296
298
|
|
297
299
|
for line in diff_output.splitlines():
|
@@ -427,7 +429,9 @@ def check_and_update_git_repo(repo_path: str) -> bool:
|
|
427
429
|
if not in_venv and (
|
428
430
|
"Permission denied" in error_msg or "not writeable" in error_msg
|
429
431
|
):
|
430
|
-
if user_confirm(
|
432
|
+
if user_confirm(
|
433
|
+
"检测到权限问题,是否尝试用户级安装(--user)?", True
|
434
|
+
):
|
431
435
|
user_result = subprocess.run(
|
432
436
|
install_cmd + ["--user"],
|
433
437
|
cwd=git_root,
|
@@ -442,7 +446,9 @@ def check_and_update_git_repo(repo_path: str) -> bool:
|
|
442
446
|
PrettyOutput.print(f"代码安装失败: {error_msg}", OutputType.ERROR)
|
443
447
|
return False
|
444
448
|
except Exception as e:
|
445
|
-
PrettyOutput.print(
|
449
|
+
PrettyOutput.print(
|
450
|
+
f"安装过程中发生意外错误: {str(e)}", OutputType.ERROR
|
451
|
+
)
|
446
452
|
return False
|
447
453
|
# 更新检查日期文件
|
448
454
|
with open(last_check_file, "w") as f:
|
@@ -476,7 +482,9 @@ def get_diff_file_list() -> List[str]:
|
|
476
482
|
subprocess.run(["git", "reset"], check=True)
|
477
483
|
|
478
484
|
if result.returncode != 0:
|
479
|
-
PrettyOutput.print(
|
485
|
+
PrettyOutput.print(
|
486
|
+
f"获取差异文件列表失败: {result.stderr}", OutputType.ERROR
|
487
|
+
)
|
480
488
|
return []
|
481
489
|
|
482
490
|
return [f for f in result.stdout.splitlines() if f]
|
@@ -626,7 +634,9 @@ def confirm_add_new_files() -> None:
|
|
626
634
|
need_confirm = True
|
627
635
|
|
628
636
|
if binary_files:
|
629
|
-
output_lines.append(
|
637
|
+
output_lines.append(
|
638
|
+
f"检测到{len(binary_files)}个二进制文件(选择N将重新检测)"
|
639
|
+
)
|
630
640
|
output_lines.append("二进制文件列表:")
|
631
641
|
output_lines.extend(f" - {file}" for file in binary_files)
|
632
642
|
need_confirm = True
|
jarvis/jarvis_utils/globals.py
CHANGED
@@ -264,7 +264,7 @@ def get_all_memory_tags() -> Dict[str, List[str]]:
|
|
264
264
|
"""
|
265
265
|
获取所有记忆类型中的标签集合。
|
266
266
|
每个类型最多返回200个标签,超过时随机提取。
|
267
|
-
|
267
|
+
|
268
268
|
返回:
|
269
269
|
Dict[str, List[str]]: 按记忆类型分组的标签列表
|
270
270
|
"""
|
@@ -272,25 +272,27 @@ def get_all_memory_tags() -> Dict[str, List[str]]:
|
|
272
272
|
import json
|
273
273
|
import random
|
274
274
|
from jarvis.jarvis_utils.config import get_data_dir
|
275
|
-
|
276
|
-
tags_by_type = {
|
275
|
+
|
276
|
+
tags_by_type: Dict[str, List[str]] = {
|
277
277
|
"short_term": [],
|
278
278
|
"project_long_term": [],
|
279
|
-
"global_long_term": []
|
279
|
+
"global_long_term": [],
|
280
280
|
}
|
281
|
-
|
281
|
+
|
282
282
|
MAX_TAGS_PER_TYPE = 200
|
283
|
-
|
283
|
+
|
284
284
|
# 获取短期记忆标签
|
285
285
|
short_term_tags = set()
|
286
286
|
for memory in short_term_memories:
|
287
287
|
short_term_tags.update(memory.get("tags", []))
|
288
288
|
short_term_tags_list = sorted(list(short_term_tags))
|
289
289
|
if len(short_term_tags_list) > MAX_TAGS_PER_TYPE:
|
290
|
-
tags_by_type["short_term"] = sorted(
|
290
|
+
tags_by_type["short_term"] = sorted(
|
291
|
+
random.sample(short_term_tags_list, MAX_TAGS_PER_TYPE)
|
292
|
+
)
|
291
293
|
else:
|
292
294
|
tags_by_type["short_term"] = short_term_tags_list
|
293
|
-
|
295
|
+
|
294
296
|
# 获取项目长期记忆标签
|
295
297
|
project_memory_dir = Path(".jarvis/memory")
|
296
298
|
if project_memory_dir.exists():
|
@@ -304,10 +306,12 @@ def get_all_memory_tags() -> Dict[str, List[str]]:
|
|
304
306
|
pass
|
305
307
|
project_tags_list = sorted(list(project_tags))
|
306
308
|
if len(project_tags_list) > MAX_TAGS_PER_TYPE:
|
307
|
-
tags_by_type["project_long_term"] = sorted(
|
309
|
+
tags_by_type["project_long_term"] = sorted(
|
310
|
+
random.sample(project_tags_list, MAX_TAGS_PER_TYPE)
|
311
|
+
)
|
308
312
|
else:
|
309
313
|
tags_by_type["project_long_term"] = project_tags_list
|
310
|
-
|
314
|
+
|
311
315
|
# 获取全局长期记忆标签
|
312
316
|
global_memory_dir = Path(get_data_dir()) / "memory" / "global_long_term"
|
313
317
|
if global_memory_dir.exists():
|
@@ -321,8 +325,10 @@ def get_all_memory_tags() -> Dict[str, List[str]]:
|
|
321
325
|
pass
|
322
326
|
global_tags_list = sorted(list(global_tags))
|
323
327
|
if len(global_tags_list) > MAX_TAGS_PER_TYPE:
|
324
|
-
tags_by_type["global_long_term"] = sorted(
|
328
|
+
tags_by_type["global_long_term"] = sorted(
|
329
|
+
random.sample(global_tags_list, MAX_TAGS_PER_TYPE)
|
330
|
+
)
|
325
331
|
else:
|
326
332
|
tags_by_type["global_long_term"] = global_tags_list
|
327
|
-
|
333
|
+
|
328
334
|
return tags_by_type
|