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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +1143 -245
- jarvis/jarvis_agent/agent_manager.py +97 -0
- jarvis/jarvis_agent/builtin_input_handler.py +12 -10
- jarvis/jarvis_agent/config_editor.py +57 -0
- jarvis/jarvis_agent/edit_file_handler.py +392 -99
- jarvis/jarvis_agent/event_bus.py +48 -0
- jarvis/jarvis_agent/events.py +157 -0
- jarvis/jarvis_agent/file_context_handler.py +79 -0
- jarvis/jarvis_agent/file_methodology_manager.py +117 -0
- jarvis/jarvis_agent/jarvis.py +1117 -147
- jarvis/jarvis_agent/main.py +78 -34
- jarvis/jarvis_agent/memory_manager.py +195 -0
- jarvis/jarvis_agent/methodology_share_manager.py +174 -0
- jarvis/jarvis_agent/prompt_manager.py +82 -0
- jarvis/jarvis_agent/prompts.py +46 -9
- jarvis/jarvis_agent/protocols.py +4 -1
- jarvis/jarvis_agent/rewrite_file_handler.py +141 -0
- jarvis/jarvis_agent/run_loop.py +146 -0
- jarvis/jarvis_agent/session_manager.py +9 -9
- jarvis/jarvis_agent/share_manager.py +228 -0
- jarvis/jarvis_agent/shell_input_handler.py +23 -3
- jarvis/jarvis_agent/stdio_redirect.py +295 -0
- jarvis/jarvis_agent/task_analyzer.py +212 -0
- jarvis/jarvis_agent/task_manager.py +154 -0
- jarvis/jarvis_agent/task_planner.py +496 -0
- jarvis/jarvis_agent/tool_executor.py +8 -4
- jarvis/jarvis_agent/tool_share_manager.py +139 -0
- jarvis/jarvis_agent/user_interaction.py +42 -0
- jarvis/jarvis_agent/utils.py +54 -0
- jarvis/jarvis_agent/web_bridge.py +189 -0
- jarvis/jarvis_agent/web_output_sink.py +53 -0
- jarvis/jarvis_agent/web_server.py +751 -0
- jarvis/jarvis_c2rust/__init__.py +26 -0
- jarvis/jarvis_c2rust/cli.py +613 -0
- jarvis/jarvis_c2rust/collector.py +258 -0
- jarvis/jarvis_c2rust/library_replacer.py +1122 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +1300 -0
- jarvis/jarvis_c2rust/optimizer.py +960 -0
- jarvis/jarvis_c2rust/scanner.py +1681 -0
- jarvis/jarvis_c2rust/transpiler.py +2325 -0
- jarvis/jarvis_code_agent/build_validation_config.py +133 -0
- jarvis/jarvis_code_agent/code_agent.py +1605 -178
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +62 -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 +102 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +59 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +69 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +38 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +38 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +50 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +93 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +129 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +54 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +154 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +363 -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 +89 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +31 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +231 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +183 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +219 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +209 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +451 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +77 -0
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +48 -0
- jarvis/jarvis_code_agent/lint.py +275 -13
- jarvis/jarvis_code_agent/utils.py +142 -0
- jarvis/jarvis_code_analysis/checklists/loader.py +20 -6
- jarvis/jarvis_code_analysis/code_review.py +583 -548
- jarvis/jarvis_data/config_schema.json +339 -28
- jarvis/jarvis_git_squash/main.py +22 -13
- jarvis/jarvis_git_utils/git_commiter.py +171 -55
- jarvis/jarvis_mcp/sse_mcp_client.py +22 -15
- jarvis/jarvis_mcp/stdio_mcp_client.py +4 -4
- jarvis/jarvis_mcp/streamable_mcp_client.py +36 -16
- jarvis/jarvis_memory_organizer/memory_organizer.py +753 -0
- jarvis/jarvis_methodology/main.py +48 -63
- jarvis/jarvis_multi_agent/__init__.py +302 -43
- jarvis/jarvis_multi_agent/main.py +70 -24
- jarvis/jarvis_platform/ai8.py +40 -23
- jarvis/jarvis_platform/base.py +210 -49
- jarvis/jarvis_platform/human.py +11 -1
- jarvis/jarvis_platform/kimi.py +82 -76
- jarvis/jarvis_platform/openai.py +73 -1
- jarvis/jarvis_platform/registry.py +8 -15
- jarvis/jarvis_platform/tongyi.py +115 -101
- jarvis/jarvis_platform/yuanbao.py +89 -63
- jarvis/jarvis_platform_manager/main.py +194 -132
- jarvis/jarvis_platform_manager/service.py +122 -86
- jarvis/jarvis_rag/cli.py +156 -53
- jarvis/jarvis_rag/embedding_manager.py +155 -12
- jarvis/jarvis_rag/llm_interface.py +10 -13
- jarvis/jarvis_rag/query_rewriter.py +63 -12
- jarvis/jarvis_rag/rag_pipeline.py +222 -40
- jarvis/jarvis_rag/reranker.py +26 -3
- jarvis/jarvis_rag/retriever.py +270 -14
- jarvis/jarvis_sec/__init__.py +3605 -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 +116 -0
- jarvis/jarvis_sec/report.py +257 -0
- jarvis/jarvis_sec/status.py +264 -0
- jarvis/jarvis_sec/types.py +20 -0
- jarvis/jarvis_sec/workflow.py +219 -0
- jarvis/jarvis_smart_shell/main.py +405 -137
- jarvis/jarvis_stats/__init__.py +13 -0
- jarvis/jarvis_stats/cli.py +387 -0
- jarvis/jarvis_stats/stats.py +711 -0
- jarvis/jarvis_stats/storage.py +612 -0
- jarvis/jarvis_stats/visualizer.py +282 -0
- jarvis/jarvis_tools/ask_user.py +1 -0
- jarvis/jarvis_tools/base.py +18 -2
- jarvis/jarvis_tools/clear_memory.py +239 -0
- jarvis/jarvis_tools/cli/main.py +220 -144
- jarvis/jarvis_tools/execute_script.py +52 -12
- jarvis/jarvis_tools/file_analyzer.py +17 -12
- jarvis/jarvis_tools/generate_new_tool.py +46 -24
- jarvis/jarvis_tools/read_code.py +277 -18
- jarvis/jarvis_tools/read_symbols.py +141 -0
- jarvis/jarvis_tools/read_webpage.py +86 -13
- jarvis/jarvis_tools/registry.py +294 -90
- jarvis/jarvis_tools/retrieve_memory.py +227 -0
- jarvis/jarvis_tools/save_memory.py +194 -0
- jarvis/jarvis_tools/search_web.py +62 -28
- jarvis/jarvis_tools/sub_agent.py +205 -0
- jarvis/jarvis_tools/sub_code_agent.py +217 -0
- jarvis/jarvis_tools/virtual_tty.py +330 -62
- jarvis/jarvis_utils/builtin_replace_map.py +4 -5
- jarvis/jarvis_utils/clipboard.py +90 -0
- jarvis/jarvis_utils/config.py +607 -50
- jarvis/jarvis_utils/embedding.py +3 -0
- jarvis/jarvis_utils/fzf.py +57 -0
- jarvis/jarvis_utils/git_utils.py +251 -29
- jarvis/jarvis_utils/globals.py +174 -17
- jarvis/jarvis_utils/http.py +58 -79
- jarvis/jarvis_utils/input.py +899 -153
- jarvis/jarvis_utils/methodology.py +210 -83
- jarvis/jarvis_utils/output.py +220 -137
- jarvis/jarvis_utils/utils.py +1906 -135
- jarvis_ai_assistant-0.7.0.dist-info/METADATA +465 -0
- jarvis_ai_assistant-0.7.0.dist-info/RECORD +192 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/entry_points.txt +8 -2
- jarvis/jarvis_git_details/main.py +0 -265
- jarvis/jarvis_platform/oyi.py +0 -357
- jarvis/jarvis_tools/edit_file.py +0 -255
- jarvis/jarvis_tools/rewrite_file.py +0 -195
- jarvis_ai_assistant-0.1.222.dist-info/METADATA +0 -767
- jarvis_ai_assistant-0.1.222.dist-info/RECORD +0 -110
- /jarvis/{jarvis_git_details → jarvis_memory_organizer}/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/licenses/LICENSE +0 -0
- {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 ""
|
jarvis/jarvis_tools/ask_user.py
CHANGED
jarvis/jarvis_tools/base.py
CHANGED
|
@@ -6,7 +6,14 @@ from typing import Any, Callable, Dict
|
|
|
6
6
|
class Tool:
|
|
7
7
|
"""工具类,用于封装工具的基本信息和执行方法"""
|
|
8
8
|
|
|
9
|
-
def __init__(
|
|
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
|
-
|
|
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}
|