jarvis-ai-assistant 0.3.17__py3-none-any.whl → 0.3.19__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 +23 -10
- jarvis/jarvis_agent/edit_file_handler.py +8 -13
- jarvis/jarvis_agent/jarvis.py +13 -3
- jarvis/jarvis_agent/memory_manager.py +4 -4
- jarvis/jarvis_agent/methodology_share_manager.py +2 -2
- jarvis/jarvis_agent/task_analyzer.py +4 -3
- jarvis/jarvis_agent/task_manager.py +6 -6
- jarvis/jarvis_agent/tool_executor.py +2 -2
- jarvis/jarvis_agent/tool_share_manager.py +2 -2
- jarvis/jarvis_code_agent/code_agent.py +21 -29
- jarvis/jarvis_code_analysis/code_review.py +2 -4
- jarvis/jarvis_data/config_schema.json +5 -0
- jarvis/jarvis_git_utils/git_commiter.py +17 -18
- jarvis/jarvis_methodology/main.py +12 -12
- jarvis/jarvis_platform/base.py +21 -13
- jarvis/jarvis_platform/kimi.py +13 -13
- jarvis/jarvis_platform/tongyi.py +17 -15
- jarvis/jarvis_platform/yuanbao.py +11 -11
- jarvis/jarvis_platform_manager/main.py +12 -22
- jarvis/jarvis_rag/cli.py +36 -32
- jarvis/jarvis_rag/embedding_manager.py +11 -6
- jarvis/jarvis_rag/llm_interface.py +6 -5
- jarvis/jarvis_rag/rag_pipeline.py +9 -8
- jarvis/jarvis_rag/reranker.py +3 -2
- jarvis/jarvis_rag/retriever.py +18 -8
- jarvis/jarvis_smart_shell/main.py +306 -46
- jarvis/jarvis_stats/stats.py +40 -0
- jarvis/jarvis_stats/storage.py +220 -9
- jarvis/jarvis_tools/clear_memory.py +0 -11
- jarvis/jarvis_tools/cli/main.py +18 -17
- jarvis/jarvis_tools/edit_file.py +4 -4
- jarvis/jarvis_tools/execute_script.py +5 -1
- jarvis/jarvis_tools/file_analyzer.py +6 -6
- jarvis/jarvis_tools/generate_new_tool.py +6 -17
- jarvis/jarvis_tools/read_code.py +3 -6
- jarvis/jarvis_tools/read_webpage.py +74 -13
- jarvis/jarvis_tools/registry.py +8 -28
- jarvis/jarvis_tools/retrieve_memory.py +5 -16
- jarvis/jarvis_tools/rewrite_file.py +0 -4
- jarvis/jarvis_tools/save_memory.py +2 -10
- jarvis/jarvis_tools/search_web.py +5 -8
- jarvis/jarvis_tools/virtual_tty.py +22 -40
- jarvis/jarvis_utils/clipboard.py +3 -3
- jarvis/jarvis_utils/config.py +8 -0
- jarvis/jarvis_utils/input.py +67 -27
- jarvis/jarvis_utils/methodology.py +3 -3
- jarvis/jarvis_utils/output.py +1 -7
- jarvis/jarvis_utils/utils.py +44 -58
- {jarvis_ai_assistant-0.3.17.dist-info → jarvis_ai_assistant-0.3.19.dist-info}/METADATA +1 -1
- {jarvis_ai_assistant-0.3.17.dist-info → jarvis_ai_assistant-0.3.19.dist-info}/RECORD +55 -55
- {jarvis_ai_assistant-0.3.17.dist-info → jarvis_ai_assistant-0.3.19.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.3.17.dist-info → jarvis_ai_assistant-0.3.19.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.3.17.dist-info → jarvis_ai_assistant-0.3.19.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.17.dist-info → jarvis_ai_assistant-0.3.19.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,13 @@ from typing import Any, Dict
|
|
3
3
|
|
4
4
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
5
5
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
6
|
+
from jarvis.jarvis_utils.config import (
|
7
|
+
get_web_search_platform_name,
|
8
|
+
get_web_search_model_name,
|
9
|
+
)
|
10
|
+
from jarvis.jarvis_utils.http import get as http_get
|
11
|
+
from markdownify import markdownify as md # type: ignore
|
12
|
+
import requests
|
6
13
|
|
7
14
|
|
8
15
|
class WebpageTool:
|
@@ -22,28 +29,82 @@ class WebpageTool:
|
|
22
29
|
}
|
23
30
|
|
24
31
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
25
|
-
"""
|
32
|
+
"""
|
33
|
+
读取网页内容。
|
34
|
+
优先使用配置的 web_search_platform 与模型的原生web能力;若不支持,则使用requests抓取页面并调用模型进行分析。
|
35
|
+
"""
|
26
36
|
try:
|
27
|
-
url = args
|
28
|
-
want = args.get("want", "请总结这个网页的主要内容")
|
37
|
+
url = str(args.get("url", "")).strip()
|
38
|
+
want = str(args.get("want", "请总结这个网页的主要内容"))
|
29
39
|
|
30
|
-
|
40
|
+
if not url:
|
41
|
+
return {"success": False, "stdout": "", "stderr": "缺少必需参数:url"}
|
42
|
+
|
43
|
+
# 1) 优先使用配置的 Web 搜索平台与模型(若支持web)
|
44
|
+
web_search_platform = get_web_search_platform_name()
|
45
|
+
web_search_model = get_web_search_model_name()
|
46
|
+
if web_search_platform and web_search_model:
|
47
|
+
model = PlatformRegistry().create_platform(web_search_platform)
|
48
|
+
if model:
|
49
|
+
model.set_model_name(web_search_model)
|
50
|
+
if model.support_web():
|
51
|
+
|
52
|
+
model.set_web(True)
|
53
|
+
model.set_suppress_output(False) # type: ignore
|
54
|
+
prompt = f"""请帮我处理这个网页:{url}
|
55
|
+
用户的具体需求是:{want}
|
56
|
+
请按照以下要求输出结果:
|
57
|
+
1. 使用Markdown格式
|
58
|
+
2. 包含网页标题
|
59
|
+
3. 根据用户需求提供准确、完整的信息"""
|
60
|
+
response = model.chat_until_success(prompt) # type: ignore
|
61
|
+
return {"success": True, "stdout": response, "stderr": ""}
|
62
|
+
|
63
|
+
# 2) 然后尝试使用默认平台(normal)的 web 能力
|
31
64
|
model = PlatformRegistry().get_normal_platform()
|
32
|
-
model.
|
33
|
-
model.set_suppress_output(False) # type: ignore
|
65
|
+
if model.support_web():
|
34
66
|
|
35
|
-
|
36
|
-
|
67
|
+
model.set_web(True)
|
68
|
+
model.set_suppress_output(False) # type: ignore
|
69
|
+
prompt = f"""请帮我处理这个网页:{url}
|
37
70
|
用户的具体需求是:{want}
|
38
71
|
请按照以下要求输出结果:
|
39
72
|
1. 使用Markdown格式
|
40
73
|
2. 包含网页标题
|
41
74
|
3. 根据用户需求提供准确、完整的信息"""
|
75
|
+
response = model.chat_until_success(prompt) # type: ignore
|
76
|
+
return {"success": True, "stdout": response, "stderr": ""}
|
77
|
+
|
78
|
+
# 3) 回退:使用 requests 抓取网页,再用模型分析
|
79
|
+
|
80
|
+
try:
|
81
|
+
resp = http_get(url, timeout=10.0, allow_redirects=True)
|
82
|
+
content_md = md(resp.text, strip=["script", "style"])
|
83
|
+
except requests.exceptions.HTTPError as e:
|
84
|
+
PrettyOutput.print(f"⚠️ HTTP错误 {e.response.status_code} 访问 {url}", OutputType.WARNING)
|
85
|
+
return {"success": False, "stdout": "", "stderr": f"HTTP错误:{e.response.status_code}"}
|
86
|
+
except requests.exceptions.RequestException as e:
|
87
|
+
PrettyOutput.print(f"⚠️ 请求错误: {e}", OutputType.WARNING)
|
88
|
+
return {"success": False, "stdout": "", "stderr": f"请求错误:{e}"}
|
89
|
+
|
90
|
+
if not content_md or not content_md.strip():
|
91
|
+
return {"success": False, "stdout": "", "stderr": "无法从网页抓取有效内容。"}
|
42
92
|
|
43
|
-
# Get response from Yuanbao model
|
44
|
-
response = model.chat_until_success(prompt) # type: ignore
|
45
93
|
|
46
|
-
|
94
|
+
summary_prompt = f"""以下是网页 {url} 的内容(已转换为Markdown):
|
95
|
+
----------------
|
96
|
+
{content_md}
|
97
|
+
----------------
|
98
|
+
请根据用户的具体需求“{want}”进行总结与回答:
|
99
|
+
- 使用Markdown格式
|
100
|
+
- 包含网页标题(若可推断)
|
101
|
+
- 提供准确、完整的信息"""
|
102
|
+
|
103
|
+
model = PlatformRegistry().get_normal_platform()
|
104
|
+
model.set_suppress_output(False) # type: ignore
|
105
|
+
summary = model.chat_until_success(summary_prompt) # type: ignore
|
106
|
+
|
107
|
+
return {"success": True, "stdout": summary, "stderr": ""}
|
47
108
|
|
48
109
|
except Exception as e:
|
49
110
|
PrettyOutput.print(f"读取网页失败: {str(e)}", OutputType.ERROR)
|
@@ -55,5 +116,5 @@ class WebpageTool:
|
|
55
116
|
|
56
117
|
@staticmethod
|
57
118
|
def check() -> bool:
|
58
|
-
"""
|
59
|
-
return
|
119
|
+
"""工具可用性检查:始终可用;若模型不支持web将回退到requests抓取。"""
|
120
|
+
return True
|
jarvis/jarvis_tools/registry.py
CHANGED
@@ -287,10 +287,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
287
287
|
for tool_name in dont_use_list:
|
288
288
|
if tool_name in self.tools:
|
289
289
|
del self.tools[tool_name]
|
290
|
-
|
291
|
-
f"已排除工具: {tool_name}",
|
292
|
-
OutputType.INFO,
|
293
|
-
)
|
290
|
+
|
294
291
|
|
295
292
|
def _load_mcp_tools(self) -> None:
|
296
293
|
"""加载MCP工具,优先从配置获取,其次从目录扫描"""
|
@@ -354,9 +351,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
354
351
|
try:
|
355
352
|
import subprocess
|
356
353
|
|
357
|
-
|
358
|
-
f"正在克隆中心工具仓库: {central_repo}", OutputType.INFO
|
359
|
-
)
|
354
|
+
|
360
355
|
subprocess.run(
|
361
356
|
["git", "clone", central_repo, central_repo_path], check=True
|
362
357
|
)
|
@@ -399,10 +394,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
399
394
|
|
400
395
|
# 检查enable标志
|
401
396
|
if not config.get("enable", True):
|
402
|
-
|
403
|
-
f"MCP配置{config.get('name', '')}已禁用(enable=false),跳过注册",
|
404
|
-
OutputType.INFO,
|
405
|
-
)
|
397
|
+
|
406
398
|
return False
|
407
399
|
|
408
400
|
name = config.get("name", "mcp")
|
@@ -414,10 +406,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
414
406
|
args.pop("agent", None)
|
415
407
|
args.pop("want", None)
|
416
408
|
ret = client.get_resource_list()
|
417
|
-
|
418
|
-
f"MCP {name} 资源列表:\n{yaml.safe_dump(ret, allow_unicode=True)}",
|
419
|
-
OutputType.TOOL,
|
420
|
-
)
|
409
|
+
|
421
410
|
return {
|
422
411
|
"success": True,
|
423
412
|
"stdout": yaml.safe_dump(ret, allow_unicode=True),
|
@@ -438,10 +427,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
438
427
|
"stderr": "缺少必需的uri参数",
|
439
428
|
}
|
440
429
|
ret = client.get_resource(args["uri"])
|
441
|
-
|
442
|
-
f"MCP {name} 获取资源:\n{yaml.safe_dump(ret, allow_unicode=True)}",
|
443
|
-
OutputType.TOOL,
|
444
|
-
)
|
430
|
+
|
445
431
|
return ret
|
446
432
|
|
447
433
|
return execute
|
@@ -452,10 +438,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
452
438
|
args.pop("agent", None)
|
453
439
|
args.pop("want", None)
|
454
440
|
ret = client.execute(tool_name, args)
|
455
|
-
|
456
|
-
f"MCP {name} {tool_name} 执行结果:\n{yaml.safe_dump(ret, allow_unicode=True)}",
|
457
|
-
OutputType.TOOL,
|
458
|
-
)
|
441
|
+
|
459
442
|
return ret
|
460
443
|
|
461
444
|
return execute
|
@@ -665,11 +648,8 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
665
648
|
yaml.safe_load(temp_data[0]) # Check if valid YAML
|
666
649
|
|
667
650
|
# Ask user for confirmation
|
668
|
-
|
669
|
-
|
670
|
-
OutputType.INFO,
|
671
|
-
)
|
672
|
-
PrettyOutput.print(fixed_content, OutputType.TOOL)
|
651
|
+
|
652
|
+
|
673
653
|
data = temp_data
|
674
654
|
except (yaml.YAMLError, EOFError, KeyboardInterrupt):
|
675
655
|
# Even after fixing, it's not valid YAML, or user cancelled.
|
@@ -147,17 +147,12 @@ class RetrieveMemoryTool:
|
|
147
147
|
|
148
148
|
# 检查是否超过token限制
|
149
149
|
if total_tokens + memory_tokens > memory_token_limit:
|
150
|
-
|
151
|
-
f"达到token限制 ({total_tokens}/{memory_token_limit}),停止加载更多记忆",
|
152
|
-
OutputType.INFO,
|
153
|
-
)
|
150
|
+
|
154
151
|
break
|
155
152
|
|
156
153
|
# 检查是否超过50条限制
|
157
154
|
if len(filtered_memories) >= 50:
|
158
|
-
|
159
|
-
f"达到记忆条数限制 (50条),停止加载更多记忆", OutputType.INFO
|
160
|
-
)
|
155
|
+
|
161
156
|
break
|
162
157
|
|
163
158
|
filtered_memories.append(memory)
|
@@ -170,10 +165,10 @@ class RetrieveMemoryTool:
|
|
170
165
|
all_memories = all_memories[:limit]
|
171
166
|
|
172
167
|
# 打印结果摘要
|
173
|
-
|
168
|
+
|
174
169
|
|
175
170
|
if tags:
|
176
|
-
|
171
|
+
pass
|
177
172
|
|
178
173
|
# 格式化为Markdown输出
|
179
174
|
markdown_output = f"# 记忆检索结果\n\n"
|
@@ -216,17 +211,11 @@ class RetrieveMemoryTool:
|
|
216
211
|
|
217
212
|
# 如果记忆较多,在终端显示摘要
|
218
213
|
if len(all_memories) > 5:
|
219
|
-
|
214
|
+
# 静默模式下不再打印摘要,完整结果已包含在返回的markdown_output中
|
220
215
|
for i, memory in enumerate(all_memories[:5]):
|
221
216
|
content_preview = memory.get("content", "")[:100]
|
222
217
|
if len(memory.get("content", "")) > 100:
|
223
218
|
content_preview += "..."
|
224
|
-
PrettyOutput.print(
|
225
|
-
f"{i+1}. [{memory.get('type')}] {memory.get('id')}\n"
|
226
|
-
f" 标签: {', '.join(memory.get('tags', []))}\n"
|
227
|
-
f" 内容: {content_preview}",
|
228
|
-
OutputType.INFO,
|
229
|
-
)
|
230
219
|
|
231
220
|
return {
|
232
221
|
"success": True,
|
@@ -114,7 +114,6 @@ class FileRewriteTool:
|
|
114
114
|
action = "创建并写入" if not file_exists else "成功重写"
|
115
115
|
stdout_message = f"文件 {abs_path} {action}"
|
116
116
|
stdout_messages.append(stdout_message)
|
117
|
-
PrettyOutput.print(stdout_message, OutputType.SUCCESS)
|
118
117
|
|
119
118
|
except Exception as e:
|
120
119
|
stderr_message = f"处理文件 {file_path} 时出错: {str(e)}"
|
@@ -126,7 +125,6 @@ class FileRewriteTool:
|
|
126
125
|
if not success and processed:
|
127
126
|
rollback_message = "操作失败,正在回滚修改..."
|
128
127
|
stderr_messages.append(rollback_message)
|
129
|
-
PrettyOutput.print(rollback_message, OutputType.WARNING)
|
130
128
|
|
131
129
|
try:
|
132
130
|
if original_content is None:
|
@@ -141,7 +139,6 @@ class FileRewriteTool:
|
|
141
139
|
rollback_file_message = f"已回滚文件: {abs_path}"
|
142
140
|
|
143
141
|
stderr_messages.append(rollback_file_message)
|
144
|
-
PrettyOutput.print(rollback_file_message, OutputType.INFO)
|
145
142
|
except Exception as e:
|
146
143
|
rollback_error = f"回滚文件 {file_path} 失败: {str(e)}"
|
147
144
|
stderr_messages.append(rollback_error)
|
@@ -172,7 +169,6 @@ class FileRewriteTool:
|
|
172
169
|
if processed:
|
173
170
|
rollback_message = "操作失败,正在回滚修改..."
|
174
171
|
stderr_messages.append(rollback_message)
|
175
|
-
PrettyOutput.print(rollback_message, OutputType.WARNING)
|
176
172
|
|
177
173
|
try:
|
178
174
|
if original_content is None:
|
@@ -159,12 +159,7 @@ class SaveMemoryTool:
|
|
159
159
|
# 打印单条记忆保存信息
|
160
160
|
memory_type = memory_data["memory_type"]
|
161
161
|
tags = memory_data.get("tags", [])
|
162
|
-
|
163
|
-
f"[{i+1}/{len(memories)}] {memory_type} 记忆已保存\n"
|
164
|
-
f"ID: {result['memory_id']}\n"
|
165
|
-
f"标签: {', '.join(tags)}",
|
166
|
-
OutputType.SUCCESS,
|
167
|
-
)
|
162
|
+
|
168
163
|
except Exception as e:
|
169
164
|
failed_count += 1
|
170
165
|
error_msg = f"保存第 {i+1} 条记忆失败: {str(e)}"
|
@@ -178,10 +173,7 @@ class SaveMemoryTool:
|
|
178
173
|
)
|
179
174
|
|
180
175
|
# 生成总结报告
|
181
|
-
|
182
|
-
f"\n批量保存完成:成功 {success_count} 条,失败 {failed_count} 条",
|
183
|
-
OutputType.INFO,
|
184
|
-
)
|
176
|
+
|
185
177
|
|
186
178
|
# 构建返回结果
|
187
179
|
output = {
|
@@ -34,7 +34,7 @@ class SearchWebTool:
|
|
34
34
|
# pylint: disable=too-many-locals, broad-except
|
35
35
|
"""执行网络搜索、抓取内容并总结结果。"""
|
36
36
|
try:
|
37
|
-
|
37
|
+
|
38
38
|
results = list(DDGS().text(query, max_results=50, page=3))
|
39
39
|
|
40
40
|
if not results:
|
@@ -50,17 +50,14 @@ class SearchWebTool:
|
|
50
50
|
|
51
51
|
for r in results:
|
52
52
|
if visited_count >= 10:
|
53
|
-
|
53
|
+
|
54
54
|
break
|
55
55
|
|
56
56
|
url = r["href"]
|
57
57
|
title = r.get("title", url)
|
58
58
|
|
59
59
|
try:
|
60
|
-
|
61
|
-
f"📄 ({visited_count + 1}/10) 正在抓取: {title} ({url})",
|
62
|
-
OutputType.INFO,
|
63
|
-
)
|
60
|
+
|
64
61
|
response = http_get(url, timeout=10.0, allow_redirects=True)
|
65
62
|
content = md(response.text, strip=["script", "style"])
|
66
63
|
if content:
|
@@ -83,9 +80,9 @@ class SearchWebTool:
|
|
83
80
|
}
|
84
81
|
|
85
82
|
url_list_str = "\n".join(f" - {u}" for u in visited_urls)
|
86
|
-
PrettyOutput.print(f"🔍 已成功访问并处理以下URL:\n{url_list_str}", OutputType.INFO)
|
87
83
|
|
88
|
-
|
84
|
+
|
85
|
+
|
89
86
|
summary_prompt = f"请为查询“{query}”总结以下内容:\n\n{full_content}"
|
90
87
|
|
91
88
|
if not agent.model:
|
@@ -3,6 +3,7 @@ import os
|
|
3
3
|
import sys
|
4
4
|
import time
|
5
5
|
from typing import Any, Dict, TYPE_CHECKING
|
6
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
6
7
|
|
7
8
|
# 为了类型检查,总是导入这些模块
|
8
9
|
if TYPE_CHECKING:
|
@@ -126,62 +127,50 @@ class VirtualTTYTool:
|
|
126
127
|
try:
|
127
128
|
if action == "launch":
|
128
129
|
if args.get("keys", "") != "":
|
129
|
-
print(
|
130
|
+
PrettyOutput.print("启动虚拟终端时,不能同时指定 keys 参数", OutputType.ERROR)
|
130
131
|
return {
|
131
132
|
"success": False,
|
132
133
|
"stdout": "",
|
133
134
|
"stderr": "启动虚拟终端时,不能同时指定keys参数",
|
134
135
|
}
|
135
|
-
|
136
|
+
|
136
137
|
result = self._launch_tty(agent, tty_id)
|
137
|
-
if result["success"]:
|
138
|
-
print(f"
|
139
|
-
else:
|
140
|
-
print(f"❌ 启动虚拟终端 [{tty_id}] 失败")
|
138
|
+
if not result["success"]:
|
139
|
+
PrettyOutput.print(f"启动虚拟终端 [{tty_id}] 失败", OutputType.ERROR)
|
141
140
|
return result
|
142
141
|
elif action == "send_keys":
|
143
142
|
keys = args.get("keys", "").strip()
|
144
143
|
add_enter = args.get("add_enter", True)
|
145
144
|
timeout = args.get("timeout", 5.0) # 默认5秒超时
|
146
|
-
|
145
|
+
|
147
146
|
result = self._input_command(agent, tty_id, keys, timeout, add_enter)
|
148
|
-
if result["success"]:
|
149
|
-
print(f"
|
150
|
-
else:
|
151
|
-
print(f"❌ 发送按键序列到终端 [{tty_id}] 失败")
|
147
|
+
if not result["success"]:
|
148
|
+
PrettyOutput.print(f"发送按键序列到终端 [{tty_id}] 失败", OutputType.ERROR)
|
152
149
|
return result
|
153
150
|
elif action == "output":
|
154
151
|
timeout = args.get("timeout", 5.0) # 默认5秒超时
|
155
|
-
|
152
|
+
|
156
153
|
result = self._get_output(agent, tty_id, timeout)
|
157
|
-
if result["success"]:
|
158
|
-
print(f"
|
159
|
-
else:
|
160
|
-
print(f"❌ 获取终端 [{tty_id}] 输出失败")
|
154
|
+
if not result["success"]:
|
155
|
+
PrettyOutput.print(f"获取终端 [{tty_id}] 输出失败", OutputType.ERROR)
|
161
156
|
return result
|
162
157
|
elif action == "close":
|
163
|
-
|
158
|
+
|
164
159
|
result = self._close_tty(agent, tty_id)
|
165
|
-
if result["success"]:
|
166
|
-
print(f"
|
167
|
-
else:
|
168
|
-
print(f"❌ 关闭虚拟终端 [{tty_id}] 失败")
|
160
|
+
if not result["success"]:
|
161
|
+
PrettyOutput.print(f"关闭虚拟终端 [{tty_id}] 失败", OutputType.ERROR)
|
169
162
|
return result
|
170
163
|
elif action == "get_screen":
|
171
|
-
|
164
|
+
|
172
165
|
result = self._get_screen(agent, tty_id)
|
173
|
-
if result["success"]:
|
174
|
-
print(f"
|
175
|
-
else:
|
176
|
-
print(f"❌ 获取终端 [{tty_id}] 屏幕内容失败")
|
166
|
+
if not result["success"]:
|
167
|
+
PrettyOutput.print(f"获取终端 [{tty_id}] 屏幕内容失败", OutputType.ERROR)
|
177
168
|
return result
|
178
169
|
elif action == "list":
|
179
|
-
|
170
|
+
|
180
171
|
result = self._list_ttys(agent)
|
181
|
-
if result["success"]:
|
182
|
-
print("
|
183
|
-
else:
|
184
|
-
print("❌ 获取虚拟终端列表失败")
|
172
|
+
if not result["success"]:
|
173
|
+
PrettyOutput.print("获取虚拟终端列表失败", OutputType.ERROR)
|
185
174
|
return result
|
186
175
|
return {"success": False, "stdout": "", "stderr": "不支持的操作"}
|
187
176
|
|
@@ -241,8 +230,7 @@ class VirtualTTYTool:
|
|
241
230
|
except BlockingIOError:
|
242
231
|
continue
|
243
232
|
|
244
|
-
|
245
|
-
print(f"📤 终端 [{tty_id}]: {output}")
|
233
|
+
|
246
234
|
|
247
235
|
return {"success": True, "stdout": output, "stderr": ""}
|
248
236
|
|
@@ -309,8 +297,7 @@ class VirtualTTYTool:
|
|
309
297
|
except _queue.Empty:
|
310
298
|
continue
|
311
299
|
|
312
|
-
|
313
|
-
print(f"📤 终端 [{tty_id}]: {output}")
|
300
|
+
|
314
301
|
|
315
302
|
return {"success": True, "stdout": output, "stderr": ""}
|
316
303
|
|
@@ -388,7 +375,6 @@ class VirtualTTYTool:
|
|
388
375
|
output += data.decode()
|
389
376
|
except BlockingIOError:
|
390
377
|
continue
|
391
|
-
print(f"📤 终端 [{tty_id}]: {output}")
|
392
378
|
return {"success": True, "stdout": output, "stderr": ""}
|
393
379
|
|
394
380
|
except Exception as e:
|
@@ -437,7 +423,6 @@ class VirtualTTYTool:
|
|
437
423
|
except Exception: # queue.Empty
|
438
424
|
continue
|
439
425
|
|
440
|
-
print(f"📤 终端 [{tty_id}]: {output}")
|
441
426
|
return {"success": True, "stdout": output, "stderr": ""}
|
442
427
|
|
443
428
|
except Exception as e:
|
@@ -490,8 +475,6 @@ class VirtualTTYTool:
|
|
490
475
|
break
|
491
476
|
except BlockingIOError:
|
492
477
|
break
|
493
|
-
print(f"📤 终端 [{tty_id}]: {output}")
|
494
|
-
|
495
478
|
return {"success": True, "stdout": output, "stderr": ""}
|
496
479
|
|
497
480
|
except Exception as e:
|
@@ -523,7 +506,6 @@ class VirtualTTYTool:
|
|
523
506
|
except Exception: # queue.Empty
|
524
507
|
continue
|
525
508
|
|
526
|
-
print(f"📤 终端 [{tty_id}]: {output}")
|
527
509
|
return {"success": True, "stdout": output, "stderr": ""}
|
528
510
|
|
529
511
|
except Exception as e:
|
jarvis/jarvis_utils/clipboard.py
CHANGED
@@ -11,9 +11,9 @@ def copy_to_clipboard(text: str) -> None:
|
|
11
11
|
参数:
|
12
12
|
text: 要复制的文本
|
13
13
|
"""
|
14
|
-
print("--- 剪贴板内容开始 ---")
|
15
|
-
print(text)
|
16
|
-
print("--- 剪贴板内容结束 ---")
|
14
|
+
PrettyOutput.print("--- 剪贴板内容开始 ---", OutputType.INFO)
|
15
|
+
PrettyOutput.print(text, OutputType.CODE, lang="text")
|
16
|
+
PrettyOutput.print("--- 剪贴板内容结束 ---", OutputType.INFO)
|
17
17
|
|
18
18
|
system = platform.system()
|
19
19
|
|
jarvis/jarvis_utils/config.py
CHANGED
@@ -624,3 +624,11 @@ def is_enable_builtin_config_selector() -> bool:
|
|
624
624
|
return (
|
625
625
|
GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_STARTUP_CONFIG_SELECTOR", False) is True
|
626
626
|
)
|
627
|
+
|
628
|
+
|
629
|
+
def is_immediate_abort() -> bool:
|
630
|
+
"""
|
631
|
+
是否启用立即中断:当在对话过程中检测到用户中断信号时,立即停止输出并返回。
|
632
|
+
默认关闭
|
633
|
+
"""
|
634
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_IMMEDIATE_ABORT", False) is True
|