jarvis-ai-assistant 0.1.222__py3-none-any.whl → 0.7.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.
Files changed (162) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +1143 -245
  3. jarvis/jarvis_agent/agent_manager.py +97 -0
  4. jarvis/jarvis_agent/builtin_input_handler.py +12 -10
  5. jarvis/jarvis_agent/config_editor.py +57 -0
  6. jarvis/jarvis_agent/edit_file_handler.py +392 -99
  7. jarvis/jarvis_agent/event_bus.py +48 -0
  8. jarvis/jarvis_agent/events.py +157 -0
  9. jarvis/jarvis_agent/file_context_handler.py +79 -0
  10. jarvis/jarvis_agent/file_methodology_manager.py +117 -0
  11. jarvis/jarvis_agent/jarvis.py +1117 -147
  12. jarvis/jarvis_agent/main.py +78 -34
  13. jarvis/jarvis_agent/memory_manager.py +195 -0
  14. jarvis/jarvis_agent/methodology_share_manager.py +174 -0
  15. jarvis/jarvis_agent/prompt_manager.py +82 -0
  16. jarvis/jarvis_agent/prompts.py +46 -9
  17. jarvis/jarvis_agent/protocols.py +4 -1
  18. jarvis/jarvis_agent/rewrite_file_handler.py +141 -0
  19. jarvis/jarvis_agent/run_loop.py +146 -0
  20. jarvis/jarvis_agent/session_manager.py +9 -9
  21. jarvis/jarvis_agent/share_manager.py +228 -0
  22. jarvis/jarvis_agent/shell_input_handler.py +23 -3
  23. jarvis/jarvis_agent/stdio_redirect.py +295 -0
  24. jarvis/jarvis_agent/task_analyzer.py +212 -0
  25. jarvis/jarvis_agent/task_manager.py +154 -0
  26. jarvis/jarvis_agent/task_planner.py +496 -0
  27. jarvis/jarvis_agent/tool_executor.py +8 -4
  28. jarvis/jarvis_agent/tool_share_manager.py +139 -0
  29. jarvis/jarvis_agent/user_interaction.py +42 -0
  30. jarvis/jarvis_agent/utils.py +54 -0
  31. jarvis/jarvis_agent/web_bridge.py +189 -0
  32. jarvis/jarvis_agent/web_output_sink.py +53 -0
  33. jarvis/jarvis_agent/web_server.py +751 -0
  34. jarvis/jarvis_c2rust/__init__.py +26 -0
  35. jarvis/jarvis_c2rust/cli.py +613 -0
  36. jarvis/jarvis_c2rust/collector.py +258 -0
  37. jarvis/jarvis_c2rust/library_replacer.py +1122 -0
  38. jarvis/jarvis_c2rust/llm_module_agent.py +1300 -0
  39. jarvis/jarvis_c2rust/optimizer.py +960 -0
  40. jarvis/jarvis_c2rust/scanner.py +1681 -0
  41. jarvis/jarvis_c2rust/transpiler.py +2325 -0
  42. jarvis/jarvis_code_agent/build_validation_config.py +133 -0
  43. jarvis/jarvis_code_agent/code_agent.py +1605 -178
  44. jarvis/jarvis_code_agent/code_analyzer/__init__.py +62 -0
  45. jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
  46. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
  47. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +102 -0
  48. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +59 -0
  49. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
  50. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +69 -0
  51. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +38 -0
  52. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +44 -0
  53. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +38 -0
  54. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +50 -0
  55. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +93 -0
  56. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +129 -0
  57. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +54 -0
  58. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +154 -0
  59. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
  60. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +363 -0
  61. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
  62. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
  63. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
  64. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
  65. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
  66. jarvis/jarvis_code_agent/code_analyzer/language_support.py +89 -0
  67. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +31 -0
  68. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +231 -0
  69. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +183 -0
  70. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +219 -0
  71. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +209 -0
  72. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +451 -0
  73. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +77 -0
  74. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +48 -0
  75. jarvis/jarvis_code_agent/lint.py +275 -13
  76. jarvis/jarvis_code_agent/utils.py +142 -0
  77. jarvis/jarvis_code_analysis/checklists/loader.py +20 -6
  78. jarvis/jarvis_code_analysis/code_review.py +583 -548
  79. jarvis/jarvis_data/config_schema.json +339 -28
  80. jarvis/jarvis_git_squash/main.py +22 -13
  81. jarvis/jarvis_git_utils/git_commiter.py +171 -55
  82. jarvis/jarvis_mcp/sse_mcp_client.py +22 -15
  83. jarvis/jarvis_mcp/stdio_mcp_client.py +4 -4
  84. jarvis/jarvis_mcp/streamable_mcp_client.py +36 -16
  85. jarvis/jarvis_memory_organizer/memory_organizer.py +753 -0
  86. jarvis/jarvis_methodology/main.py +48 -63
  87. jarvis/jarvis_multi_agent/__init__.py +302 -43
  88. jarvis/jarvis_multi_agent/main.py +70 -24
  89. jarvis/jarvis_platform/ai8.py +40 -23
  90. jarvis/jarvis_platform/base.py +210 -49
  91. jarvis/jarvis_platform/human.py +11 -1
  92. jarvis/jarvis_platform/kimi.py +82 -76
  93. jarvis/jarvis_platform/openai.py +73 -1
  94. jarvis/jarvis_platform/registry.py +8 -15
  95. jarvis/jarvis_platform/tongyi.py +115 -101
  96. jarvis/jarvis_platform/yuanbao.py +89 -63
  97. jarvis/jarvis_platform_manager/main.py +194 -132
  98. jarvis/jarvis_platform_manager/service.py +122 -86
  99. jarvis/jarvis_rag/cli.py +156 -53
  100. jarvis/jarvis_rag/embedding_manager.py +155 -12
  101. jarvis/jarvis_rag/llm_interface.py +10 -13
  102. jarvis/jarvis_rag/query_rewriter.py +63 -12
  103. jarvis/jarvis_rag/rag_pipeline.py +222 -40
  104. jarvis/jarvis_rag/reranker.py +26 -3
  105. jarvis/jarvis_rag/retriever.py +270 -14
  106. jarvis/jarvis_sec/__init__.py +3605 -0
  107. jarvis/jarvis_sec/checkers/__init__.py +32 -0
  108. jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
  109. jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
  110. jarvis/jarvis_sec/cli.py +116 -0
  111. jarvis/jarvis_sec/report.py +257 -0
  112. jarvis/jarvis_sec/status.py +264 -0
  113. jarvis/jarvis_sec/types.py +20 -0
  114. jarvis/jarvis_sec/workflow.py +219 -0
  115. jarvis/jarvis_smart_shell/main.py +405 -137
  116. jarvis/jarvis_stats/__init__.py +13 -0
  117. jarvis/jarvis_stats/cli.py +387 -0
  118. jarvis/jarvis_stats/stats.py +711 -0
  119. jarvis/jarvis_stats/storage.py +612 -0
  120. jarvis/jarvis_stats/visualizer.py +282 -0
  121. jarvis/jarvis_tools/ask_user.py +1 -0
  122. jarvis/jarvis_tools/base.py +18 -2
  123. jarvis/jarvis_tools/clear_memory.py +239 -0
  124. jarvis/jarvis_tools/cli/main.py +220 -144
  125. jarvis/jarvis_tools/execute_script.py +52 -12
  126. jarvis/jarvis_tools/file_analyzer.py +17 -12
  127. jarvis/jarvis_tools/generate_new_tool.py +46 -24
  128. jarvis/jarvis_tools/read_code.py +277 -18
  129. jarvis/jarvis_tools/read_symbols.py +141 -0
  130. jarvis/jarvis_tools/read_webpage.py +86 -13
  131. jarvis/jarvis_tools/registry.py +294 -90
  132. jarvis/jarvis_tools/retrieve_memory.py +227 -0
  133. jarvis/jarvis_tools/save_memory.py +194 -0
  134. jarvis/jarvis_tools/search_web.py +62 -28
  135. jarvis/jarvis_tools/sub_agent.py +205 -0
  136. jarvis/jarvis_tools/sub_code_agent.py +217 -0
  137. jarvis/jarvis_tools/virtual_tty.py +330 -62
  138. jarvis/jarvis_utils/builtin_replace_map.py +4 -5
  139. jarvis/jarvis_utils/clipboard.py +90 -0
  140. jarvis/jarvis_utils/config.py +607 -50
  141. jarvis/jarvis_utils/embedding.py +3 -0
  142. jarvis/jarvis_utils/fzf.py +57 -0
  143. jarvis/jarvis_utils/git_utils.py +251 -29
  144. jarvis/jarvis_utils/globals.py +174 -17
  145. jarvis/jarvis_utils/http.py +58 -79
  146. jarvis/jarvis_utils/input.py +899 -153
  147. jarvis/jarvis_utils/methodology.py +210 -83
  148. jarvis/jarvis_utils/output.py +220 -137
  149. jarvis/jarvis_utils/utils.py +1906 -135
  150. jarvis_ai_assistant-0.7.0.dist-info/METADATA +465 -0
  151. jarvis_ai_assistant-0.7.0.dist-info/RECORD +192 -0
  152. {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/entry_points.txt +8 -2
  153. jarvis/jarvis_git_details/main.py +0 -265
  154. jarvis/jarvis_platform/oyi.py +0 -357
  155. jarvis/jarvis_tools/edit_file.py +0 -255
  156. jarvis/jarvis_tools/rewrite_file.py +0 -195
  157. jarvis_ai_assistant-0.1.222.dist-info/METADATA +0 -767
  158. jarvis_ai_assistant-0.1.222.dist-info/RECORD +0 -110
  159. /jarvis/{jarvis_git_details → jarvis_memory_organizer}/__init__.py +0 -0
  160. {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/WHEEL +0 -0
  161. {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/licenses/LICENSE +0 -0
  162. {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,282 @@
1
+ """
2
+ 统计数据可视化模块
3
+
4
+ 提供终端图形化展示功能
5
+ """
6
+
7
+ import os
8
+ import io
9
+ from typing import Dict, List, Optional, Any
10
+ from collections import OrderedDict
11
+ import plotext as plt
12
+ from rich.console import Console
13
+ from rich.table import Table
14
+ from rich.panel import Panel
15
+ from rich import box
16
+
17
+
18
+ class StatsVisualizer:
19
+ """统计数据可视化类"""
20
+
21
+ def __init__(self, width: Optional[int] = None, height: Optional[int] = None):
22
+ """
23
+ 初始化可视化器
24
+
25
+ Args:
26
+ width: 图表宽度,默认为终端宽度-10
27
+ height: 图表高度,默认为20
28
+ """
29
+ self.width = width or self._get_terminal_width() - 10
30
+ self.height = height or 20
31
+
32
+ # 确保最小尺寸
33
+ self.width = max(self.width, 40)
34
+ self.height = max(self.height, 10)
35
+
36
+ # 初始化Rich Console
37
+ self.console = Console()
38
+
39
+ def _get_terminal_width(self) -> int:
40
+ """获取终端宽度"""
41
+ try:
42
+ columns = os.get_terminal_size().columns
43
+ return columns
44
+ except Exception:
45
+ return 80
46
+
47
+ def plot_line_chart(
48
+ self,
49
+ data: Dict[str, float],
50
+ title: str = "",
51
+ unit: Optional[str] = None,
52
+ show_values: bool = True,
53
+ ) -> str:
54
+ """
55
+ 使用 plotext 绘制折线图
56
+ """
57
+ if not data:
58
+ return "无数据可显示"
59
+
60
+ sorted_data = OrderedDict(sorted(data.items()))
61
+ labels = list(sorted_data.keys())
62
+ values = list(sorted_data.values())
63
+
64
+ plt.clf()
65
+ plt.plotsize(self.width, self.height)
66
+ plt.plot(values)
67
+ plt.xticks(range(len(labels)), labels)
68
+ if title:
69
+ plt.title(title)
70
+ if unit:
71
+ plt.ylabel(unit)
72
+
73
+ chart = plt.build()
74
+
75
+ if show_values and values:
76
+ min_val = min(values)
77
+ max_val = max(values)
78
+ avg_val = sum(values) / len(values)
79
+ stats_info_text = (
80
+ f"最小值: {min_val:.2f}, 最大值: {max_val:.2f}, 平均值: {avg_val:.2f}"
81
+ )
82
+
83
+ # 使用StringIO捕获Panel输出
84
+ string_io = io.StringIO()
85
+ temp_console = Console(file=string_io, width=self.width)
86
+ temp_console.print(
87
+ Panel(
88
+ stats_info_text,
89
+ title="[bold]数据统计[/bold]",
90
+ expand=False,
91
+ style="dim",
92
+ border_style="blue",
93
+ )
94
+ )
95
+ stats_panel_str = string_io.getvalue()
96
+
97
+ return chart + "\n" + stats_panel_str.strip()
98
+ return chart
99
+
100
+ def plot_bar_chart(
101
+ self,
102
+ data: Dict[str, float],
103
+ title: str = "",
104
+ unit: Optional[str] = None,
105
+ horizontal: bool = False,
106
+ ) -> str:
107
+ """
108
+ 使用 plotext 绘制柱状图
109
+ """
110
+ if not data:
111
+ return "无数据可显示"
112
+
113
+ labels = list(data.keys())
114
+ values = list(data.values())
115
+
116
+ plt.clf()
117
+ plt.plotsize(self.width, self.height)
118
+
119
+ if horizontal:
120
+ plt.bar(labels, values, orientation="horizontal")
121
+ else:
122
+ plt.bar(labels, values)
123
+ if title:
124
+ plt.title(title)
125
+ if unit:
126
+ plt.ylabel(unit)
127
+
128
+ return plt.build()
129
+
130
+ def show_summary(
131
+ self,
132
+ aggregated_data: Dict[str, Dict[str, Any]],
133
+ metric_name: str,
134
+ unit: Optional[str] = None,
135
+ tags_filter: Optional[Dict[str, str]] = None,
136
+ ) -> str:
137
+ """
138
+ 显示数据摘要
139
+
140
+ Args:
141
+ aggregated_data: 聚合后的数据
142
+ metric_name: 指标名称
143
+ unit: 单位
144
+ tags_filter: 标签过滤条件
145
+
146
+ Returns:
147
+ 摘要字符串(用于兼容性,实际会直接打印)
148
+ """
149
+ if not aggregated_data:
150
+ self.console.print("[yellow]无数据可显示[/yellow]")
151
+ return "无数据可显示"
152
+
153
+ # 创建表格
154
+ table = Table(title=f"{metric_name} 统计摘要", box=box.ROUNDED)
155
+
156
+ # 添加列
157
+ table.add_column("时间", justify="center", style="cyan")
158
+ table.add_column("计数", justify="right", style="green")
159
+ table.add_column("总和", justify="right", style="yellow")
160
+ table.add_column("平均", justify="right", style="yellow")
161
+ table.add_column("最小", justify="right", style="blue")
162
+ table.add_column("最大", justify="right", style="red")
163
+
164
+ # 添加数据行
165
+ for time_key, stats in sorted(aggregated_data.items()):
166
+ table.add_row(
167
+ time_key,
168
+ str(stats["count"]),
169
+ f"{stats['sum']:.2f}",
170
+ f"{stats['avg']:.2f}",
171
+ f"{stats['min']:.2f}",
172
+ f"{stats['max']:.2f}",
173
+ )
174
+
175
+ # 显示表格
176
+ self.console.print(table)
177
+
178
+ # 显示单位信息
179
+ if unit:
180
+ self.console.print(f"\n[dim]单位: {unit}[/dim]")
181
+
182
+ # 显示过滤条件
183
+ if tags_filter:
184
+ filter_str = ", ".join([f"{k}={v}" for k, v in tags_filter.items()])
185
+ self.console.print(f"[dim]过滤条件: {filter_str}[/dim]")
186
+
187
+ return "" # 返回空字符串,实际输出已经通过console打印
188
+
189
+ def show_table(
190
+ self,
191
+ records: List[Dict[str, Any]],
192
+ metric_name: str,
193
+ unit: Optional[str] = None,
194
+ start_time: Optional[str] = None,
195
+ end_time: Optional[str] = None,
196
+ tags_filter: Optional[Dict[str, str]] = None,
197
+ ) -> str:
198
+ """
199
+ 使用Rich Table显示数据记录
200
+
201
+ Args:
202
+ records: 数据记录列表
203
+ metric_name: 指标名称
204
+ unit: 单位
205
+ start_time: 开始时间
206
+ end_time: 结束时间
207
+ tags_filter: 标签过滤条件
208
+
209
+ Returns:
210
+ 空字符串(实际通过console打印)
211
+ """
212
+ if not records:
213
+ self.console.print(f"[yellow]没有找到指标 '{metric_name}' 的数据[/yellow]")
214
+ return ""
215
+
216
+ # 创建表格
217
+ table = Table(title=f"指标: {metric_name}", box=box.ROUNDED)
218
+
219
+ # 添加列
220
+ table.add_column("时间", style="cyan", no_wrap=True)
221
+ table.add_column("值", justify="right", style="yellow")
222
+ table.add_column("标签", style="dim")
223
+
224
+ # 只显示最近的20条记录
225
+ display_records = records[-20:] if len(records) > 20 else records
226
+
227
+ # 添加数据行
228
+ from datetime import datetime
229
+
230
+ for record in display_records:
231
+ timestamp = datetime.fromisoformat(record["timestamp"])
232
+ time_str = timestamp.strftime("%Y-%m-%d %H:%M:%S")
233
+ value = f"{record['value']:.2f}"
234
+ tags_str = ", ".join(f"{k}={v}" for k, v in record.get("tags", {}).items())
235
+
236
+ table.add_row(time_str, value, tags_str)
237
+
238
+ # 显示表格
239
+ self.console.print(table)
240
+
241
+ # 显示元信息
242
+ info_items = []
243
+ if unit:
244
+ info_items.append(f"单位: {unit}")
245
+ if start_time and end_time:
246
+ info_items.append(f"时间范围: [cyan]{start_time}[/] ~ [cyan]{end_time}[/]")
247
+ if tags_filter:
248
+ filter_str = ", ".join([f"{k}={v}" for k, v in tags_filter.items()])
249
+ info_items.append(f"过滤条件: {filter_str}")
250
+
251
+ if info_items:
252
+ self.console.print(
253
+ Panel(
254
+ " | ".join(info_items),
255
+ title="[bold]查询详情[/bold]",
256
+ expand=False,
257
+ style="dim",
258
+ border_style="green",
259
+ )
260
+ )
261
+
262
+ # 统计信息
263
+ if len(records) > 0:
264
+ values = [r["value"] for r in records]
265
+ stats_info_text = (
266
+ f"总记录数: {len(records)} | "
267
+ f"显示: {len(display_records)} | "
268
+ f"最小值: {min(values):.2f} | "
269
+ f"最大值: {max(values):.2f} | "
270
+ f"平均值: {sum(values)/len(values):.2f}"
271
+ )
272
+ self.console.print(
273
+ Panel(
274
+ stats_info_text,
275
+ title="[bold]数据统计[/bold]",
276
+ expand=False,
277
+ style="dim",
278
+ border_style="blue",
279
+ )
280
+ )
281
+
282
+ return ""
@@ -34,6 +34,7 @@ class AskUserTool:
34
34
 
35
35
  # 获取agent对象并重置工具调用计数
36
36
  agent = args["agent"]
37
+ agent.set_run_input_handlers_next_turn(True)
37
38
 
38
39
  # 显示问题给用户
39
40
  PrettyOutput.print(f"问题: {question}", OutputType.SYSTEM)
@@ -6,7 +6,14 @@ from typing import Any, Callable, Dict
6
6
  class Tool:
7
7
  """工具类,用于封装工具的基本信息和执行方法"""
8
8
 
9
- def __init__(self, name: str, description: str, parameters: Dict, func: Callable):
9
+ def __init__(
10
+ self,
11
+ name: str,
12
+ description: str,
13
+ parameters: Dict,
14
+ func: Callable,
15
+ protocol_version: str = "1.0",
16
+ ):
10
17
  """
11
18
  初始化工具对象
12
19
 
@@ -15,11 +22,13 @@ class Tool:
15
22
  description (str): 工具描述
16
23
  parameters (Dict): 工具参数定义
17
24
  func (Callable): 工具执行函数
25
+ protocol_version (str): 工具协议版本,默认"1.0";支持"1.0"或"2.0"
18
26
  """
19
27
  self.name = name
20
28
  self.description = description
21
29
  self.parameters = parameters
22
30
  self.func = func
31
+ self.protocol_version = protocol_version
23
32
 
24
33
  def to_dict(self) -> Dict:
25
34
  """将工具对象转换为字典格式,主要用于序列化"""
@@ -39,4 +48,11 @@ class Tool:
39
48
  返回:
40
49
  Dict[str, Any]: 工具执行结果
41
50
  """
42
- return self.func(arguments)
51
+ try:
52
+ return self.func(arguments)
53
+ except Exception as e:
54
+ return {
55
+ "success": False,
56
+ "stderr": f"工具 {self.name} 执行失败: {str(e)}",
57
+ "stdout": "",
58
+ }
@@ -0,0 +1,239 @@
1
+ # -*- coding: utf-8 -*-
2
+ import json
3
+ from pathlib import Path
4
+ from typing import Any, Dict, List, Optional
5
+
6
+ from jarvis.jarvis_utils.config import get_data_dir
7
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
8
+ from jarvis.jarvis_utils.globals import (
9
+ clear_short_term_memories,
10
+ short_term_memories,
11
+ )
12
+
13
+
14
+ class ClearMemoryTool:
15
+ """清除记忆工具,用于批量清除指定的记忆"""
16
+
17
+ name = "clear_memory"
18
+ description = """批量清除指定的记忆。
19
+
20
+ 支持的清除方式:
21
+ 1. 按记忆类型清除所有记忆
22
+ 2. 按标签清除特定记忆
23
+ 3. 按记忆ID清除单个记忆
24
+
25
+ 支持的记忆类型:
26
+ - project_long_term: 项目长期记忆
27
+ - global_long_term: 全局长期记忆
28
+ - short_term: 短期记忆
29
+ - all: 所有类型的记忆
30
+
31
+ 注意:清除操作不可恢复,请谨慎使用
32
+ """
33
+
34
+ parameters = {
35
+ "type": "object",
36
+ "properties": {
37
+ "memory_types": {
38
+ "type": "array",
39
+ "items": {
40
+ "type": "string",
41
+ "enum": [
42
+ "project_long_term",
43
+ "global_long_term",
44
+ "short_term",
45
+ "all",
46
+ ],
47
+ },
48
+ "description": "要清除的记忆类型列表",
49
+ },
50
+ "tags": {
51
+ "type": "array",
52
+ "items": {"type": "string"},
53
+ "description": "要清除的记忆标签列表(可选,如果指定则只清除带有这些标签的记忆)",
54
+ },
55
+ "memory_ids": {
56
+ "type": "array",
57
+ "items": {"type": "string"},
58
+ "description": "要清除的具体记忆ID列表(可选)",
59
+ },
60
+ "confirm": {
61
+ "type": "boolean",
62
+ "description": "确认清除操作(必须为true才会执行清除)",
63
+ "default": False,
64
+ },
65
+ },
66
+ "required": ["memory_types", "confirm"],
67
+ }
68
+
69
+ def __init__(self):
70
+ """初始化清除记忆工具"""
71
+ self.project_memory_dir = Path(".jarvis/memory")
72
+ self.global_memory_dir = Path(get_data_dir()) / "memory"
73
+
74
+ def _get_memory_dir(self, memory_type: str) -> Path:
75
+ """根据记忆类型获取存储目录"""
76
+ if memory_type == "project_long_term":
77
+ return self.project_memory_dir
78
+ elif memory_type in ["global_long_term", "short_term"]:
79
+ return self.global_memory_dir / memory_type
80
+ else:
81
+ raise ValueError(f"未知的记忆类型: {memory_type}")
82
+
83
+ def _clear_short_term_memories(
84
+ self, tags: Optional[List[str]] = None, memory_ids: Optional[List[str]] = None
85
+ ) -> Dict[str, int]:
86
+ """清除短期记忆"""
87
+ global short_term_memories
88
+
89
+ initial_count = len(short_term_memories)
90
+ removed_count = 0
91
+
92
+ if memory_ids:
93
+ # 按ID清除
94
+ new_memories = []
95
+ for memory in short_term_memories:
96
+ if memory.get("id") not in memory_ids:
97
+ new_memories.append(memory)
98
+ else:
99
+ removed_count += 1
100
+ short_term_memories[:] = new_memories
101
+ elif tags:
102
+ # 按标签清除
103
+ new_memories = []
104
+ for memory in short_term_memories:
105
+ memory_tags = memory.get("tags", [])
106
+ if not any(tag in memory_tags for tag in tags):
107
+ new_memories.append(memory)
108
+ else:
109
+ removed_count += 1
110
+ short_term_memories[:] = new_memories
111
+ else:
112
+ # 清除所有
113
+ clear_short_term_memories()
114
+ removed_count = initial_count
115
+
116
+ return {"total": initial_count, "removed": removed_count}
117
+
118
+ def _clear_long_term_memories(
119
+ self,
120
+ memory_type: str,
121
+ tags: Optional[List[str]] = None,
122
+ memory_ids: Optional[List[str]] = None,
123
+ ) -> Dict[str, int]:
124
+ """清除长期记忆"""
125
+ memory_dir = self._get_memory_dir(memory_type)
126
+
127
+ if not memory_dir.exists():
128
+ return {"total": 0, "removed": 0}
129
+
130
+ total_count = 0
131
+ removed_count = 0
132
+
133
+ # 获取所有记忆文件
134
+ memory_files = list(memory_dir.glob("*.json"))
135
+ total_count = len(memory_files)
136
+
137
+ for memory_file in memory_files:
138
+ try:
139
+ # 读取记忆内容
140
+ with open(memory_file, "r", encoding="utf-8") as f:
141
+ memory_data = json.load(f)
142
+
143
+ should_remove = False
144
+
145
+ if memory_ids:
146
+ # 按ID判断
147
+ if memory_data.get("id") in memory_ids:
148
+ should_remove = True
149
+ elif tags:
150
+ # 按标签判断
151
+ memory_tags = memory_data.get("tags", [])
152
+ if any(tag in memory_tags for tag in tags):
153
+ should_remove = True
154
+ else:
155
+ # 清除所有
156
+ should_remove = True
157
+
158
+ if should_remove:
159
+ memory_file.unlink()
160
+ removed_count += 1
161
+
162
+ except Exception as e:
163
+ PrettyOutput.print(
164
+ f"处理记忆文件 {memory_file} 时出错: {str(e)}", OutputType.WARNING
165
+ )
166
+
167
+ # 如果目录为空,可以删除目录
168
+ if not any(memory_dir.iterdir()) and memory_dir != self.project_memory_dir:
169
+ memory_dir.rmdir()
170
+
171
+ return {"total": total_count, "removed": removed_count}
172
+
173
+ def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
174
+ """执行清除记忆操作"""
175
+ try:
176
+ memory_types = args.get("memory_types", [])
177
+ tags = args.get("tags", [])
178
+ memory_ids = args.get("memory_ids", [])
179
+ confirm = args.get("confirm", False)
180
+
181
+ if not confirm:
182
+ return {
183
+ "success": False,
184
+ "stdout": "",
185
+ "stderr": "必须设置 confirm=true 才能执行清除操作",
186
+ }
187
+
188
+ # 确定要清除的记忆类型
189
+ if "all" in memory_types:
190
+ types_to_clear = ["project_long_term", "global_long_term", "short_term"]
191
+ else:
192
+ types_to_clear = memory_types
193
+
194
+ # 统计结果
195
+ results = {}
196
+ total_removed = 0
197
+
198
+ # 清除各类型的记忆
199
+ for memory_type in types_to_clear:
200
+ if memory_type == "short_term":
201
+ result = self._clear_short_term_memories(tags, memory_ids)
202
+ else:
203
+ result = self._clear_long_term_memories(
204
+ memory_type, tags, memory_ids
205
+ )
206
+
207
+ results[memory_type] = result
208
+ total_removed += result["removed"]
209
+
210
+ # 生成结果报告
211
+
212
+ # 详细报告
213
+ report = "# 记忆清除报告\n\n"
214
+ report += f"**总计清除**: {total_removed} 条记忆\n\n"
215
+
216
+ if tags:
217
+ report += f"**使用标签过滤**: {', '.join(tags)}\n\n"
218
+
219
+ if memory_ids:
220
+ report += f"**指定记忆ID**: {', '.join(memory_ids)}\n\n"
221
+
222
+ report += "## 详细结果\n\n"
223
+
224
+ for memory_type, result in results.items():
225
+ report += f"### {memory_type}\n"
226
+ report += f"- 原有记忆: {result['total']} 条\n"
227
+ report += f"- 已清除: {result['removed']} 条\n"
228
+ report += f"- 剩余: {result['total'] - result['removed']} 条\n\n"
229
+
230
+ return {
231
+ "success": True,
232
+ "stdout": report,
233
+ "stderr": "",
234
+ }
235
+
236
+ except Exception as e:
237
+ error_msg = f"清除记忆失败: {str(e)}"
238
+ PrettyOutput.print(error_msg, OutputType.ERROR)
239
+ return {"success": False, "stdout": "", "stderr": error_msg}