jarvis-ai-assistant 0.3.30__py3-none-any.whl → 0.7.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +458 -152
  3. jarvis/jarvis_agent/agent_manager.py +17 -13
  4. jarvis/jarvis_agent/builtin_input_handler.py +2 -6
  5. jarvis/jarvis_agent/config_editor.py +2 -7
  6. jarvis/jarvis_agent/event_bus.py +82 -12
  7. jarvis/jarvis_agent/file_context_handler.py +329 -0
  8. jarvis/jarvis_agent/file_methodology_manager.py +3 -4
  9. jarvis/jarvis_agent/jarvis.py +628 -55
  10. jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
  11. jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
  12. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
  13. jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
  14. jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
  15. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
  16. jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
  17. jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
  18. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
  19. jarvis/jarvis_agent/language_support_info.py +486 -0
  20. jarvis/jarvis_agent/main.py +34 -10
  21. jarvis/jarvis_agent/memory_manager.py +7 -16
  22. jarvis/jarvis_agent/methodology_share_manager.py +10 -16
  23. jarvis/jarvis_agent/prompt_manager.py +1 -1
  24. jarvis/jarvis_agent/prompts.py +193 -171
  25. jarvis/jarvis_agent/protocols.py +8 -12
  26. jarvis/jarvis_agent/run_loop.py +105 -9
  27. jarvis/jarvis_agent/session_manager.py +2 -3
  28. jarvis/jarvis_agent/share_manager.py +20 -22
  29. jarvis/jarvis_agent/shell_input_handler.py +1 -2
  30. jarvis/jarvis_agent/stdio_redirect.py +295 -0
  31. jarvis/jarvis_agent/task_analyzer.py +31 -6
  32. jarvis/jarvis_agent/task_manager.py +11 -27
  33. jarvis/jarvis_agent/tool_executor.py +2 -3
  34. jarvis/jarvis_agent/tool_share_manager.py +12 -24
  35. jarvis/jarvis_agent/utils.py +5 -1
  36. jarvis/jarvis_agent/web_bridge.py +189 -0
  37. jarvis/jarvis_agent/web_output_sink.py +53 -0
  38. jarvis/jarvis_agent/web_server.py +786 -0
  39. jarvis/jarvis_c2rust/__init__.py +26 -0
  40. jarvis/jarvis_c2rust/cli.py +575 -0
  41. jarvis/jarvis_c2rust/collector.py +250 -0
  42. jarvis/jarvis_c2rust/constants.py +26 -0
  43. jarvis/jarvis_c2rust/library_replacer.py +1254 -0
  44. jarvis/jarvis_c2rust/llm_module_agent.py +1272 -0
  45. jarvis/jarvis_c2rust/loaders.py +207 -0
  46. jarvis/jarvis_c2rust/models.py +28 -0
  47. jarvis/jarvis_c2rust/optimizer.py +2157 -0
  48. jarvis/jarvis_c2rust/scanner.py +1681 -0
  49. jarvis/jarvis_c2rust/transpiler.py +2983 -0
  50. jarvis/jarvis_c2rust/utils.py +385 -0
  51. jarvis/jarvis_code_agent/build_validation_config.py +132 -0
  52. jarvis/jarvis_code_agent/code_agent.py +1371 -220
  53. jarvis/jarvis_code_agent/code_analyzer/__init__.py +65 -0
  54. jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
  55. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
  56. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +106 -0
  57. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +74 -0
  58. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
  59. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +72 -0
  60. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +70 -0
  61. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +53 -0
  62. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +47 -0
  63. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +61 -0
  64. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +110 -0
  65. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +154 -0
  66. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +110 -0
  67. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +153 -0
  68. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
  69. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +648 -0
  70. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
  71. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
  72. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
  73. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
  74. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
  75. jarvis/jarvis_code_agent/code_analyzer/language_support.py +110 -0
  76. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +49 -0
  77. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +299 -0
  78. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +215 -0
  79. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
  80. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
  81. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +269 -0
  82. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +281 -0
  83. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
  84. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +605 -0
  85. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
  86. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +252 -0
  87. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +58 -0
  88. jarvis/jarvis_code_agent/lint.py +501 -8
  89. jarvis/jarvis_code_agent/utils.py +141 -0
  90. jarvis/jarvis_code_analysis/code_review.py +493 -584
  91. jarvis/jarvis_data/config_schema.json +128 -12
  92. jarvis/jarvis_git_squash/main.py +4 -5
  93. jarvis/jarvis_git_utils/git_commiter.py +82 -75
  94. jarvis/jarvis_mcp/sse_mcp_client.py +22 -29
  95. jarvis/jarvis_mcp/stdio_mcp_client.py +12 -13
  96. jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
  97. jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
  98. jarvis/jarvis_methodology/main.py +32 -48
  99. jarvis/jarvis_multi_agent/__init__.py +287 -55
  100. jarvis/jarvis_multi_agent/main.py +36 -4
  101. jarvis/jarvis_platform/base.py +524 -202
  102. jarvis/jarvis_platform/human.py +7 -8
  103. jarvis/jarvis_platform/kimi.py +30 -36
  104. jarvis/jarvis_platform/openai.py +88 -25
  105. jarvis/jarvis_platform/registry.py +26 -10
  106. jarvis/jarvis_platform/tongyi.py +24 -25
  107. jarvis/jarvis_platform/yuanbao.py +32 -43
  108. jarvis/jarvis_platform_manager/main.py +66 -77
  109. jarvis/jarvis_platform_manager/service.py +8 -13
  110. jarvis/jarvis_rag/cli.py +53 -55
  111. jarvis/jarvis_rag/embedding_manager.py +13 -18
  112. jarvis/jarvis_rag/llm_interface.py +8 -9
  113. jarvis/jarvis_rag/query_rewriter.py +10 -21
  114. jarvis/jarvis_rag/rag_pipeline.py +24 -27
  115. jarvis/jarvis_rag/reranker.py +4 -5
  116. jarvis/jarvis_rag/retriever.py +28 -30
  117. jarvis/jarvis_sec/__init__.py +305 -0
  118. jarvis/jarvis_sec/agents.py +143 -0
  119. jarvis/jarvis_sec/analysis.py +276 -0
  120. jarvis/jarvis_sec/checkers/__init__.py +32 -0
  121. jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
  122. jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
  123. jarvis/jarvis_sec/cli.py +139 -0
  124. jarvis/jarvis_sec/clustering.py +1439 -0
  125. jarvis/jarvis_sec/file_manager.py +427 -0
  126. jarvis/jarvis_sec/parsers.py +73 -0
  127. jarvis/jarvis_sec/prompts.py +268 -0
  128. jarvis/jarvis_sec/report.py +336 -0
  129. jarvis/jarvis_sec/review.py +453 -0
  130. jarvis/jarvis_sec/status.py +264 -0
  131. jarvis/jarvis_sec/types.py +20 -0
  132. jarvis/jarvis_sec/utils.py +499 -0
  133. jarvis/jarvis_sec/verification.py +848 -0
  134. jarvis/jarvis_sec/workflow.py +226 -0
  135. jarvis/jarvis_smart_shell/main.py +38 -87
  136. jarvis/jarvis_stats/cli.py +2 -2
  137. jarvis/jarvis_stats/stats.py +8 -8
  138. jarvis/jarvis_stats/storage.py +15 -21
  139. jarvis/jarvis_stats/visualizer.py +1 -1
  140. jarvis/jarvis_tools/clear_memory.py +3 -20
  141. jarvis/jarvis_tools/cli/main.py +21 -23
  142. jarvis/jarvis_tools/edit_file.py +1019 -132
  143. jarvis/jarvis_tools/execute_script.py +83 -25
  144. jarvis/jarvis_tools/file_analyzer.py +6 -9
  145. jarvis/jarvis_tools/generate_new_tool.py +14 -21
  146. jarvis/jarvis_tools/lsp_client.py +1552 -0
  147. jarvis/jarvis_tools/methodology.py +2 -3
  148. jarvis/jarvis_tools/read_code.py +1736 -35
  149. jarvis/jarvis_tools/read_symbols.py +140 -0
  150. jarvis/jarvis_tools/read_webpage.py +12 -13
  151. jarvis/jarvis_tools/registry.py +427 -200
  152. jarvis/jarvis_tools/retrieve_memory.py +20 -19
  153. jarvis/jarvis_tools/rewrite_file.py +72 -158
  154. jarvis/jarvis_tools/save_memory.py +3 -15
  155. jarvis/jarvis_tools/search_web.py +18 -18
  156. jarvis/jarvis_tools/sub_agent.py +36 -43
  157. jarvis/jarvis_tools/sub_code_agent.py +25 -26
  158. jarvis/jarvis_tools/virtual_tty.py +55 -33
  159. jarvis/jarvis_utils/clipboard.py +7 -10
  160. jarvis/jarvis_utils/config.py +232 -45
  161. jarvis/jarvis_utils/embedding.py +8 -5
  162. jarvis/jarvis_utils/fzf.py +8 -8
  163. jarvis/jarvis_utils/git_utils.py +225 -36
  164. jarvis/jarvis_utils/globals.py +3 -3
  165. jarvis/jarvis_utils/http.py +1 -1
  166. jarvis/jarvis_utils/input.py +99 -48
  167. jarvis/jarvis_utils/jsonnet_compat.py +465 -0
  168. jarvis/jarvis_utils/methodology.py +52 -48
  169. jarvis/jarvis_utils/utils.py +819 -491
  170. jarvis_ai_assistant-0.7.6.dist-info/METADATA +600 -0
  171. jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
  172. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +4 -0
  173. jarvis/jarvis_agent/config.py +0 -92
  174. jarvis/jarvis_agent/edit_file_handler.py +0 -296
  175. jarvis/jarvis_platform/ai8.py +0 -332
  176. jarvis/jarvis_tools/ask_user.py +0 -54
  177. jarvis_ai_assistant-0.3.30.dist-info/METADATA +0 -381
  178. jarvis_ai_assistant-0.3.30.dist-info/RECORD +0 -137
  179. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
  180. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
  181. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
@@ -4,22 +4,21 @@ sub_code_agent 工具
4
4
  将子任务交给 CodeAgent 执行,并返回执行结果。
5
5
 
6
6
  约定:
7
- - 仅接收一个参数:task
7
+ - 必填参数:task
8
+ - 可选参数:background
8
9
  - 不依赖父 Agent,所有配置使用系统默认与全局变量
9
10
  - 子Agent必须自动完成(auto_complete=True)且需要summary(need_summary=True)
10
11
  """
11
12
  from typing import Any, Dict, List
12
- import json
13
13
 
14
14
  from jarvis.jarvis_code_agent.code_agent import CodeAgent
15
15
  from jarvis.jarvis_utils.globals import delete_agent
16
16
  from jarvis.jarvis_utils.config import set_config, get_git_check_mode
17
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
18
17
 
19
18
 
20
19
  class SubCodeAgentTool:
21
20
  """
22
- 使用 CodeAgent 托管执行子任务,执行完立即清理内部 Agent。
21
+ 使用 CodeAgent 托管执行子任务,执行完立即清理 CodeAgent 实例。
23
22
  - 不注册至全局
24
23
  - 使用系统默认/全局配置
25
24
  - 启用自动完成与总结
@@ -27,7 +26,7 @@ class SubCodeAgentTool:
27
26
 
28
27
  # 必须与文件名一致,供 ToolRegistry 自动注册
29
28
  name = "sub_code_agent"
30
- description = "将子任务交给 CodeAgent 执行,并返回执行结果(使用系统默认配置,自动完成并生成总结)。"
29
+ description = "将子任务交给 CodeAgent 执行并返回结果(自动完成并生成总结)。"
31
30
  parameters = {
32
31
  "type": "object",
33
32
  "properties": {
@@ -84,6 +83,7 @@ class SubCodeAgentTool:
84
83
  parent_agent = None
85
84
  except Exception:
86
85
  parent_agent = None
86
+ parent_non_interactive = getattr(parent_agent, "non_interactive", None) if parent_agent is not None else None
87
87
  model_group = None
88
88
  use_tools: List[str] = []
89
89
  try:
@@ -108,21 +108,20 @@ class SubCodeAgentTool:
108
108
  pass
109
109
 
110
110
  # 依据父Agent已启用工具集,推导 append_tools(作为在 CodeAgent 基础工具上的增量)
111
+ # 禁用 sub_agent 和 sub_code_agent,避免无限递归
112
+ forbidden_tools = {"sub_agent", "sub_code_agent"}
111
113
  append_tools = None
112
114
  try:
113
115
  base_tools = [
114
116
  "execute_script",
115
- "search_web",
116
- "ask_user",
117
117
  "read_code",
118
+ "edit_file",
118
119
  "rewrite_file",
119
- "save_memory",
120
- "retrieve_memory",
121
- "clear_memory",
122
- "sub_code_agent",
120
+ "lsp_client",
123
121
  ]
124
122
  if use_tools:
125
- extras = [t for t in use_tools if t not in base_tools]
123
+ # 过滤掉基础工具和禁止的工具
124
+ extras = [t for t in use_tools if t not in base_tools and t not in forbidden_tools]
126
125
  append_tools = ",".join(extras) if extras else None
127
126
  except Exception:
128
127
  append_tools = None
@@ -138,6 +137,7 @@ class SubCodeAgentTool:
138
137
  need_summary=True,
139
138
  append_tools=append_tools,
140
139
  tool_group=tool_group,
140
+ non_interactive=parent_non_interactive,
141
141
  )
142
142
  except SystemExit as se:
143
143
  # 将底层 sys.exit 转换为工具错误,避免终止进程
@@ -155,21 +155,24 @@ class SubCodeAgentTool:
155
155
 
156
156
  # 子Agent需要自动完成
157
157
  try:
158
- code_agent.agent.auto_complete = True
159
- # 同步父Agent工具使用集(如可用)
158
+ code_agent.auto_complete = True
159
+ # 同步父Agent工具使用集(如可用),但禁用 sub_agent 和 sub_code_agent 避免无限递归
160
160
  if use_tools:
161
- code_agent.agent.set_use_tools(use_tools)
161
+ forbidden_tools = {"sub_agent", "sub_code_agent"}
162
+ filtered_tools = [t for t in use_tools if t not in forbidden_tools]
163
+ if filtered_tools:
164
+ code_agent.set_use_tools(filtered_tools)
162
165
  # 同步父Agent的模型名称(如可用),以尽量保持平台与模型一致
163
166
  if (
164
167
  parent_agent is not None
165
168
  and getattr(parent_agent, "model", None)
166
- and getattr(code_agent.agent, "model", None)
169
+ and getattr(code_agent, "model", None)
167
170
  ):
168
171
  try:
169
172
  parent_model_name = parent_agent.model.name() # type: ignore[attr-defined]
170
173
  if parent_model_name:
171
174
  from typing import Any
172
- model_obj: Any = getattr(code_agent.agent, "model", None)
175
+ model_obj: Any = getattr(code_agent, "model", None)
173
176
  if model_obj is not None:
174
177
  model_obj.set_model_name(parent_model_name)
175
178
  # 模型有效性校验与回退,确保父Agent模型在子Agent平台上可用
@@ -179,10 +182,7 @@ class SubCodeAgentTool:
179
182
  available_names = [m for m, _ in available_models]
180
183
  current_model_name = model_obj.name()
181
184
  if current_model_name not in available_names:
182
- PrettyOutput.print(
183
- f"检测到子CodeAgent模型 {current_model_name} 不存在于平台 {model_obj.platform_name()} 的可用模型列表,将回退到 {available_names[0]}",
184
- OutputType.WARNING,
185
- )
185
+ print(f"⚠️ 检测到子CodeAgent模型 {current_model_name} 不存在于平台 {model_obj.platform_name()} 的可用模型列表,将回退到 {available_names[0]}")
186
186
  model_obj.set_model_name(available_names[0])
187
187
  except Exception:
188
188
  # 获取模型列表或设置模型失败时,保持原设置并继续,交由底层报错处理
@@ -194,18 +194,17 @@ class SubCodeAgentTool:
194
194
 
195
195
  # 执行子任务(无提交信息前后缀)
196
196
  ret = code_agent.run(enhanced_task, prefix="", suffix="")
197
- stdout = ret if isinstance(ret, str) and ret else "任务执行完成"
198
197
 
199
- # 主动清理内部 Agent,避免污染父Agent的全局状态
198
+ # 主动清理 CodeAgent 实例,避免污染父Agent的全局状态
200
199
  try:
201
- inner_agent = code_agent.agent
202
- delete_agent(inner_agent.name)
200
+ # CodeAgent 现在直接继承 Agent,所以直接使用 code_agent
201
+ delete_agent(code_agent.name)
203
202
  except Exception:
204
203
  pass
205
204
 
206
205
  return {
207
206
  "success": True,
208
- "stdout": json.dumps({"result": stdout}, ensure_ascii=False, indent=2),
207
+ "stdout": ret,
209
208
  "stderr": "",
210
209
  }
211
210
  except Exception as e:
@@ -3,7 +3,6 @@ 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
7
6
 
8
7
  # 为了类型检查,总是导入这些模块
9
8
  if TYPE_CHECKING:
@@ -19,12 +18,7 @@ else:
19
18
 
20
19
  class VirtualTTYTool:
21
20
  name = "virtual_tty"
22
- description = (
23
- "控制虚拟终端执行各种操作,如启动终端、输入命令、获取输出等。"
24
- + "与execute_script不同,此工具会创建一个持久的虚拟终端会话,可以连续执行多个命令,并保持终端状态。"
25
- + "适用于需要交互式操作的场景,如运行需要用户输入的交互式程序(如:ssh连接、sftp传输、gdb/dlv调试等)。"
26
- + "注意:Windows平台功能有限,某些Unix特有功能可能不可用。"
27
- )
21
+ description = "控制虚拟终端执行交互式操作(如ssh、sftp、gdb等)。与execute_script不同,此工具创建持久会话,保持终端状态。Windows平台功能有限。"
28
22
  parameters = {
29
23
  "type": "object",
30
24
  "properties": {
@@ -42,19 +36,19 @@ class VirtualTTYTool:
42
36
  },
43
37
  "keys": {
44
38
  "type": "string",
45
- "description": "要发送的按键序列(仅支持单行输入,当action为send_keys时有效)",
39
+ "description": "要发送的按键序列(仅当action为send_keys时有效)",
46
40
  },
47
41
  "add_enter": {
48
42
  "type": "boolean",
49
- "description": "是否在单行命令末尾自动添加回车符(仅当action为send_keys时有效,默认为true)",
43
+ "description": "是否在命令末尾自动添加回车符(仅当action为send_keys时有效,默认true)",
50
44
  },
51
45
  "timeout": {
52
46
  "type": "number",
53
- "description": "等待输出的超时时间(秒,仅当action为send_keys或output时有效,默认为5.0)",
47
+ "description": "等待输出的超时时间(秒,仅当action为send_keys或output时有效,默认5.0)",
54
48
  },
55
49
  "tty_id": {
56
50
  "type": "string",
57
- "description": "虚拟终端的唯一标识符(默认为'default')",
51
+ "description": "虚拟终端的唯一标识符(默认'default')",
58
52
  },
59
53
  },
60
54
  "required": ["action"],
@@ -83,6 +77,8 @@ class VirtualTTYTool:
83
77
  # 确保agent有tty_sessions字典
84
78
  if not hasattr(agent, "tty_sessions"):
85
79
  agent.tty_sessions = {}
80
+ elif agent.tty_sessions is None:
81
+ agent.tty_sessions = {}
86
82
 
87
83
  # 如果指定的tty_id不存在,为其创建一个新的tty_data
88
84
  if tty_id not in agent.tty_sessions:
@@ -116,9 +112,7 @@ class VirtualTTYTool:
116
112
  try:
117
113
  if action == "launch":
118
114
  if args.get("keys", "") != "":
119
- PrettyOutput.print(
120
- "启动虚拟终端时,不能同时指定 keys 参数", OutputType.ERROR
121
- )
115
+ print("❌ 启动虚拟终端时,不能同时指定 keys 参数")
122
116
  return {
123
117
  "success": False,
124
118
  "stdout": "",
@@ -127,9 +121,7 @@ class VirtualTTYTool:
127
121
 
128
122
  result = self._launch_tty(agent, tty_id)
129
123
  if not result["success"]:
130
- PrettyOutput.print(
131
- f"启动虚拟终端 [{tty_id}] 失败", OutputType.ERROR
132
- )
124
+ print(f"❌ 启动虚拟终端 [{tty_id}] 失败")
133
125
  return result
134
126
  elif action == "send_keys":
135
127
  keys = args.get("keys", "").strip()
@@ -138,40 +130,32 @@ class VirtualTTYTool:
138
130
 
139
131
  result = self._input_command(agent, tty_id, keys, timeout, add_enter)
140
132
  if not result["success"]:
141
- PrettyOutput.print(
142
- f"发送按键序列到终端 [{tty_id}] 失败", OutputType.ERROR
143
- )
133
+ print(f"❌ 发送按键序列到终端 [{tty_id}] 失败")
144
134
  return result
145
135
  elif action == "output":
146
136
  timeout = args.get("timeout", 5.0) # 默认5秒超时
147
137
 
148
138
  result = self._get_output(agent, tty_id, timeout)
149
139
  if not result["success"]:
150
- PrettyOutput.print(
151
- f"获取终端 [{tty_id}] 输出失败", OutputType.ERROR
152
- )
140
+ print(f"❌ 获取终端 [{tty_id}] 输出失败")
153
141
  return result
154
142
  elif action == "close":
155
143
 
156
144
  result = self._close_tty(agent, tty_id)
157
145
  if not result["success"]:
158
- PrettyOutput.print(
159
- f"关闭虚拟终端 [{tty_id}] 失败", OutputType.ERROR
160
- )
146
+ print(f"❌ 关闭虚拟终端 [{tty_id}] 失败")
161
147
  return result
162
148
  elif action == "get_screen":
163
149
 
164
150
  result = self._get_screen(agent, tty_id)
165
151
  if not result["success"]:
166
- PrettyOutput.print(
167
- f"获取终端 [{tty_id}] 屏幕内容失败", OutputType.ERROR
168
- )
152
+ print(f"❌ 获取终端 [{tty_id}] 屏幕内容失败")
169
153
  return result
170
154
  elif action == "list":
171
155
 
172
156
  result = self._list_ttys(agent)
173
157
  if not result["success"]:
174
- PrettyOutput.print("获取虚拟终端列表失败", OutputType.ERROR)
158
+ print("获取虚拟终端列表失败")
175
159
  return result
176
160
  return {"success": False, "stdout": "", "stderr": "不支持的操作"}
177
161
 
@@ -231,6 +215,8 @@ class VirtualTTYTool:
231
215
  except BlockingIOError:
232
216
  continue
233
217
 
218
+ if output:
219
+ print(f"📥 启动终端时的初始输出 [{tty_id}]:\n{output}")
234
220
  return {"success": True, "stdout": output, "stderr": ""}
235
221
 
236
222
  except Exception as e:
@@ -279,7 +265,7 @@ class VirtualTTYTool:
279
265
  line = process.stdout.readline()
280
266
  if line:
281
267
  agent.tty_sessions[tty_id]["output_queue"].put(line)
282
- except:
268
+ except Exception:
283
269
  break
284
270
 
285
271
  output_thread = _threading.Thread(target=read_output, daemon=True)
@@ -296,6 +282,8 @@ class VirtualTTYTool:
296
282
  except _queue.Empty:
297
283
  continue
298
284
 
285
+ if output:
286
+ print(f"📥 启动终端时的初始输出 [{tty_id}]:\n{output}")
299
287
  return {"success": True, "stdout": output, "stderr": ""}
300
288
 
301
289
  except Exception as e:
@@ -372,6 +360,8 @@ class VirtualTTYTool:
372
360
  output += data.decode()
373
361
  except BlockingIOError:
374
362
  continue
363
+ if output:
364
+ print(f"📥 命令执行后的输出内容 [{tty_id}]:\n{output}")
375
365
  return {"success": True, "stdout": output, "stderr": ""}
376
366
 
377
367
  except Exception as e:
@@ -420,6 +410,8 @@ class VirtualTTYTool:
420
410
  except Exception: # queue.Empty
421
411
  continue
422
412
 
413
+ if output:
414
+ print(f"📥 命令执行后的输出内容 [{tty_id}]:\n{output}")
423
415
  return {"success": True, "stdout": output, "stderr": ""}
424
416
 
425
417
  except Exception as e:
@@ -472,6 +464,8 @@ class VirtualTTYTool:
472
464
  break
473
465
  except BlockingIOError:
474
466
  break
467
+ if output:
468
+ print(f"📥 获取到的输出内容 [{tty_id}]:\n{output}")
475
469
  return {"success": True, "stdout": output, "stderr": ""}
476
470
 
477
471
  except Exception as e:
@@ -503,6 +497,8 @@ class VirtualTTYTool:
503
497
  except Exception: # queue.Empty
504
498
  continue
505
499
 
500
+ if output:
501
+ print(f"📥 获取到的输出内容 [{tty_id}]:\n{output}")
506
502
  return {"success": True, "stdout": output, "stderr": ""}
507
503
 
508
504
  except Exception as e:
@@ -568,9 +564,35 @@ class VirtualTTYTool:
568
564
  }
569
565
 
570
566
  try:
567
+ process = agent.tty_sessions[tty_id]["process"]
571
568
  # 终止进程
572
- agent.tty_sessions[tty_id]["process"].terminate()
573
- agent.tty_sessions[tty_id]["process"].wait()
569
+ try:
570
+ import subprocess as _subprocess # pylint: disable=import-outside-toplevel
571
+ process.terminate()
572
+ process.wait(timeout=2)
573
+ except _subprocess.TimeoutExpired:
574
+ try:
575
+ process.kill()
576
+ process.wait()
577
+ except Exception:
578
+ pass
579
+ except Exception:
580
+ try:
581
+ process.kill()
582
+ process.wait()
583
+ except Exception:
584
+ pass
585
+ finally:
586
+ # 确保所有文件描述符被关闭
587
+ try:
588
+ if process.stdin:
589
+ process.stdin.close()
590
+ if process.stdout:
591
+ process.stdout.close()
592
+ if process.stderr:
593
+ process.stderr.close()
594
+ except Exception:
595
+ pass
574
596
 
575
597
  # 重置终端数据
576
598
  import queue as _queue # pylint: disable=import-outside-toplevel
@@ -2,7 +2,6 @@
2
2
  import platform
3
3
  import subprocess
4
4
 
5
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
6
5
 
7
6
 
8
7
  def copy_to_clipboard(text: str) -> None:
@@ -11,9 +10,9 @@ def copy_to_clipboard(text: str) -> None:
11
10
  参数:
12
11
  text: 要复制的文本
13
12
  """
14
- PrettyOutput.print("--- 剪贴板内容开始 ---", OutputType.INFO)
13
+ print("ℹ️ --- 剪贴板内容开始 ---")
15
14
  print(text)
16
- PrettyOutput.print("--- 剪贴板内容结束 ---", OutputType.INFO)
15
+ print("ℹ️ --- 剪贴板内容结束 ---")
17
16
 
18
17
  system = platform.system()
19
18
 
@@ -33,7 +32,7 @@ def copy_to_clipboard(text: str) -> None:
33
32
  process.stdin.close()
34
33
  return
35
34
  except Exception as e:
36
- PrettyOutput.print(f"使用Windows clip命令时出错: {e}", OutputType.WARNING)
35
+ print(f"⚠️ 使用Windows clip命令时出错: {e}")
37
36
 
38
37
  # macOS系统
39
38
  elif system == "Darwin":
@@ -49,7 +48,7 @@ def copy_to_clipboard(text: str) -> None:
49
48
  process.stdin.close()
50
49
  return
51
50
  except Exception as e:
52
- PrettyOutput.print(f"使用macOS pbcopy命令时出错: {e}", OutputType.WARNING)
51
+ print(f"⚠️ 使用macOS pbcopy命令时出错: {e}")
53
52
 
54
53
  # Linux系统
55
54
  else:
@@ -68,7 +67,7 @@ def copy_to_clipboard(text: str) -> None:
68
67
  except FileNotFoundError:
69
68
  pass # xsel 未安装,继续尝试下一个
70
69
  except Exception as e:
71
- PrettyOutput.print(f"使用xsel时出错: {e}", OutputType.WARNING)
70
+ print(f"⚠️ 使用xsel时出错: {e}")
72
71
 
73
72
  # 尝试使用 xclip
74
73
  try:
@@ -83,8 +82,6 @@ def copy_to_clipboard(text: str) -> None:
83
82
  process.stdin.close()
84
83
  return
85
84
  except FileNotFoundError:
86
- PrettyOutput.print(
87
- "xsel 和 xclip 均未安装, 无法复制到剪贴板", OutputType.WARNING
88
- )
85
+ print("⚠️ xsel 和 xclip 均未安装, 无法复制到剪贴板")
89
86
  except Exception as e:
90
- PrettyOutput.print(f"使用xclip时出错: {e}", OutputType.WARNING)
87
+ print(f"⚠️ 使用xclip时出错: {e}")