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
@@ -13,7 +13,6 @@ import sys
13
13
  import base64
14
14
  from typing import Iterable, List, Optional
15
15
  import wcwidth
16
-
17
16
  from colorama import Fore
18
17
  from colorama import Style as ColoramaStyle
19
18
  from fuzzywuzzy import process
@@ -35,11 +34,9 @@ from prompt_toolkit.layout.containers import Window
35
34
  from prompt_toolkit.layout.controls import FormattedTextControl
36
35
  from prompt_toolkit.layout.layout import Layout
37
36
  from prompt_toolkit.styles import Style as PromptStyle
38
-
39
37
  from jarvis.jarvis_utils.clipboard import copy_to_clipboard
40
38
  from jarvis.jarvis_utils.config import get_data_dir, get_replace_map
41
39
  from jarvis.jarvis_utils.globals import get_message_history
42
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
43
40
  from jarvis.jarvis_utils.tag import ot
44
41
 
45
42
  # Sentinel value to indicate that Ctrl+O was pressed
@@ -54,9 +51,8 @@ FZF_REQUEST_ALL_SENTINEL_PREFIX = "__FZF_REQUEST_ALL__::"
54
51
  # Persistent hint marker for multiline input (shown only once across runs)
55
52
  _MULTILINE_HINT_MARK_FILE = os.path.join(get_data_dir(), "multiline_enter_hint_shown")
56
53
 
57
-
58
54
  def _display_width(s: str) -> int:
59
- """Calculate printable width of a string in terminal columns (handles wide chars)."""
55
+ """计算字符串在终端中的可打印宽度(处理宽字符)"""
60
56
  try:
61
57
  w = 0
62
58
  for ch in s:
@@ -69,11 +65,10 @@ def _display_width(s: str) -> int:
69
65
  except Exception:
70
66
  return len(s)
71
67
 
72
-
73
68
  def _calc_prompt_rows(prev_text: str) -> int:
74
69
  """
75
- Estimate how many terminal rows the previous prompt occupied.
76
- Considers prompt prefix and soft-wrapping across terminal columns.
70
+ 估算上一个提示占用了多少终端行数。
71
+ 考虑提示前缀和跨终端列的软换行。
77
72
  """
78
73
  try:
79
74
  cols = os.get_terminal_size().columns
@@ -102,17 +97,15 @@ def _calc_prompt_rows(prev_text: str) -> int:
102
97
  total_rows += rows
103
98
  return max(1, total_rows)
104
99
 
105
-
106
100
  def _multiline_hint_already_shown() -> bool:
107
- """Check if the multiline Enter hint has been shown before (persisted)."""
101
+ """检查是否已显示过多行输入提示(持久化存储)"""
108
102
  try:
109
103
  return os.path.exists(_MULTILINE_HINT_MARK_FILE)
110
104
  except Exception:
111
105
  return False
112
106
 
113
-
114
107
  def _mark_multiline_hint_shown() -> None:
115
- """Persist that the multiline Enter hint has been shown."""
108
+ """持久化存储多行输入提示已显示的状态。"""
116
109
  try:
117
110
  os.makedirs(os.path.dirname(_MULTILINE_HINT_MARK_FILE), exist_ok=True)
118
111
  with open(_MULTILINE_HINT_MARK_FILE, "w", encoding="utf-8") as f:
@@ -121,7 +114,6 @@ def _mark_multiline_hint_shown() -> None:
121
114
  # Non-critical persistence failure; ignore to avoid breaking input flow
122
115
  pass
123
116
 
124
-
125
117
  def get_single_line_input(tip: str, default: str = "") -> str:
126
118
  """
127
119
  获取支持历史记录的单行输入。
@@ -133,7 +125,6 @@ def get_single_line_input(tip: str, default: str = "") -> str:
133
125
  prompt = FormattedText([("class:prompt", f"👤 > {tip}")])
134
126
  return session.prompt(prompt, default=default, style=style)
135
127
 
136
-
137
128
  def get_choice(tip: str, choices: List[str]) -> str:
138
129
  """
139
130
  提供一个可滚动的选择列表供用户选择。
@@ -229,7 +220,6 @@ def get_choice(tip: str, choices: List[str]) -> str:
229
220
  except (KeyboardInterrupt, EOFError):
230
221
  return ""
231
222
 
232
-
233
223
  class FileCompleter(Completer):
234
224
  """
235
225
  带有模糊匹配的文件路径自定义补全器。
@@ -363,25 +353,63 @@ class FileCompleter(Completer):
363
353
  return tag
364
354
 
365
355
 
356
+ # ---------------------
357
+ # 公共判定辅助函数(按当前Agent优先)
358
+ # ---------------------
359
+ def _get_current_agent_for_input():
360
+ try:
361
+ import jarvis.jarvis_utils.globals as g
362
+ current_name = getattr(g, "current_agent_name", "")
363
+ if current_name:
364
+ return g.get_agent(current_name)
365
+ except Exception:
366
+ pass
367
+ return None
368
+ def _is_non_interactive_for_current_agent() -> bool:
369
+ try:
370
+ from jarvis.jarvis_utils.config import is_non_interactive
371
+ ag = _get_current_agent_for_input()
372
+ try:
373
+ return bool(getattr(ag, "non_interactive", False)) if ag else bool(is_non_interactive())
374
+ except Exception:
375
+ return bool(is_non_interactive())
376
+ except Exception:
377
+ return False
378
+ def _is_auto_complete_for_current_agent() -> bool:
379
+ try:
380
+ from jarvis.jarvis_utils.config import GLOBAL_CONFIG_DATA
381
+ ag = _get_current_agent_for_input()
382
+ if ag is not None and hasattr(ag, "auto_complete"):
383
+ try:
384
+ return bool(getattr(ag, "auto_complete", False))
385
+ except Exception:
386
+ pass
387
+ env_v = os.getenv("JARVIS_AUTO_COMPLETE")
388
+ if env_v is not None:
389
+ return str(env_v).strip().lower() in ("1", "true", "yes", "on")
390
+ return bool(GLOBAL_CONFIG_DATA.get("JARVIS_AUTO_COMPLETE", False))
391
+ except Exception:
392
+ return False
366
393
  def user_confirm(tip: str, default: bool = True) -> bool:
367
- """提示用户确认是/否问题"""
394
+ """提示用户确认是/否问题(按当前Agent优先判断非交互)"""
368
395
  try:
396
+ if _is_non_interactive_for_current_agent():
397
+ return default
369
398
  suffix = "[Y/n]" if default else "[y/N]"
370
399
  ret = get_single_line_input(f"{tip} {suffix}: ")
371
400
  return default if ret == "" else ret.lower() == "y"
372
401
  except KeyboardInterrupt:
373
402
  return False
374
403
 
375
-
376
404
  def _show_history_and_copy():
377
405
  """
378
- Displays message history and handles copying to clipboard.
379
- This function uses standard I/O and is safe to call outside a prompt session.
406
+ 显示消息历史记录并处理复制到剪贴板。
407
+ 此函数使用标准I/O,可在提示会话之外安全调用。
380
408
  """
381
409
 
382
410
  history = get_message_history()
383
411
  if not history:
384
- PrettyOutput.print("没有可复制的消息", OutputType.INFO)
412
+ print("ℹ️ 没有可复制的消息")
385
413
  return
386
414
 
387
415
  # 为避免 PrettyOutput 在循环中为每行加框,先拼接后统一打印
@@ -393,8 +421,8 @@ def _show_history_and_copy():
393
421
  (cleaned_msg[:70] + "...") if len(cleaned_msg) > 70 else cleaned_msg
394
422
  )
395
423
  lines.append(f" {i + 1}: {display_msg.strip()}")
396
- lines.append("=" * 58 + "\n")
397
- PrettyOutput.print("\n".join(lines), OutputType.INFO)
424
+ lines.append("=" * 58 + "\n")
425
+ print("ℹ️ " + "\n".join(lines))
398
426
 
399
427
  while True:
400
428
  try:
@@ -403,11 +431,11 @@ def _show_history_and_copy():
403
431
 
404
432
  if not choice_str: # User pressed Enter
405
433
  if not history:
406
- PrettyOutput.print("没有历史记录可供选择。", OutputType.INFO)
434
+ print("ℹ️ 没有历史记录可供选择。")
407
435
  break
408
436
  choice = len(history) - 1
409
437
  elif choice_str.lower() == "c":
410
- PrettyOutput.print("已取消", OutputType.INFO)
438
+ print("ℹ️ 已取消")
411
439
  break
412
440
  else:
413
441
  choice = int(choice_str) - 1
@@ -415,19 +443,16 @@ def _show_history_and_copy():
415
443
  if 0 <= choice < len(history):
416
444
  selected_msg = history[choice]
417
445
  copy_to_clipboard(selected_msg)
418
- PrettyOutput.print(
419
- f"已复制消息: {selected_msg[:70]}...", OutputType.SUCCESS
420
- )
446
+ print(f"✅ 已复制消息: {selected_msg[:70]}...")
421
447
  break
422
448
  else:
423
- PrettyOutput.print("无效的序号,请重试。", OutputType.WARNING)
449
+ print("⚠️ 无效的序号,请重试。")
424
450
  except ValueError:
425
- PrettyOutput.print("无效的输入,请输入数字。", OutputType.WARNING)
451
+ print("⚠️ 无效的输入,请输入数字。")
426
452
  except (KeyboardInterrupt, EOFError):
427
- PrettyOutput.print("\n操作取消", OutputType.INFO)
453
+ print("\nℹ️ 操作取消")
428
454
  break
429
455
 
430
-
431
456
  def _get_multiline_input_internal(
432
457
  tip: str, preset: Optional[str] = None, preset_cursor: Optional[int] = None
433
458
  ) -> str:
@@ -447,10 +472,7 @@ def _get_multiline_input_internal(
447
472
  first_enter_hint_shown = True
448
473
 
449
474
  def _show_notice():
450
- PrettyOutput.print(
451
- "提示:当前支持多行输入。输入完成请使用 Ctrl+J 确认;Enter 仅用于换行。",
452
- OutputType.INFO,
453
- )
475
+ print("ℹ️ 提示:当前支持多行输入。输入完成请使用 Ctrl+J 确认;Enter 仅用于换行。")
454
476
  try:
455
477
  input("按回车继续...")
456
478
  except Exception:
@@ -482,7 +504,7 @@ def _get_multiline_input_internal(
482
504
  """Handle Ctrl+O by exiting the prompt and returning the sentinel value."""
483
505
  event.app.exit(result=CTRL_O_SENTINEL)
484
506
 
485
- @bindings.add("c-t", filter=has_focus(DEFAULT_BUFFER))
507
+ @bindings.add("c-t", filter=has_focus(DEFAULT_BUFFER), eager=True)
486
508
  def _(event):
487
509
  """Return a shell command like '!bash' for upper input_handler to execute."""
488
510
 
@@ -650,7 +672,6 @@ def _get_multiline_input_internal(
650
672
  except (KeyboardInterrupt, EOFError):
651
673
  return ""
652
674
 
653
-
654
675
  def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
655
676
  """
656
677
  获取带有增强补全和确认功能的多行输入。
@@ -663,6 +684,40 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
663
684
  preset: Optional[str] = None
664
685
  preset_cursor: Optional[int] = None
665
686
  while True:
687
+ # 基于“当前Agent”精确判断非交互与自动完成,避免多Agent相互干扰
688
+ if _is_non_interactive_for_current_agent():
689
+ # 在多Agent系统中,无论是否启用自动完成,均提示可用智能体并建议使用 SEND_MESSAGE 转移控制权
690
+ hint = ""
691
+ try:
692
+ ag = _get_current_agent_for_input()
693
+ ohs = getattr(ag, "output_handler", [])
694
+ available_agents: List[str] = []
695
+ for oh in (ohs or []):
696
+ cfgs = getattr(oh, "agents_config", None)
697
+ if isinstance(cfgs, list):
698
+ for c in cfgs:
699
+ try:
700
+ name = c.get("name")
701
+ except Exception:
702
+ name = None
703
+ if isinstance(name, str) and name.strip():
704
+ available_agents.append(name.strip())
705
+ if available_agents:
706
+ # 去重但保留顺序
707
+ seen = set()
708
+ ordered = []
709
+ for n in available_agents:
710
+ if n not in seen:
711
+ seen.add(n)
712
+ ordered.append(n)
713
+ hint = "\n当前可用智能体: " + ", ".join(ordered) + f"\n如需将任务交给其他智能体,请使用 {ot('SEND_MESSAGE')} 块。"
714
+ except Exception:
715
+ hint = ""
716
+ if _is_auto_complete_for_current_agent():
717
+ base_msg = "我无法与你交互,所有的事情你都自我决策,如果无法决策,就完成任务。输出" + ot("!!!COMPLETE!!!")
718
+ return base_msg + hint
719
+ else:
720
+ return "我无法与你交互,所有的事情你都自我决策" + hint
666
721
  user_input = _get_multiline_input_internal(
667
722
  tip, preset=preset, preset_cursor=preset_cursor
668
723
  )
@@ -695,9 +750,7 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
695
750
  import subprocess
696
751
 
697
752
  if shutil.which("fzf") is None:
698
- PrettyOutput.print(
699
- "未检测到 fzf,无法打开文件选择器。", OutputType.WARNING
700
- )
753
+ print("⚠️ 未检测到 fzf,无法打开文件选择器。")
701
754
  else:
702
755
  files = []
703
756
  try:
@@ -726,7 +779,7 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
726
779
  break
727
780
 
728
781
  if not files:
729
- PrettyOutput.print("未找到可选择的文件。", OutputType.INFO)
782
+ print("ℹ️ 未找到可选择的文件。")
730
783
  else:
731
784
  try:
732
785
  specials = [
@@ -770,7 +823,7 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
770
823
  if sel:
771
824
  selected_path = sel
772
825
  except Exception as e:
773
- PrettyOutput.print(f"FZF 执行失败: {e}", OutputType.ERROR)
826
+ print(f"FZF 执行失败: {e}")
774
827
 
775
828
  # Compute new text based on selection (or keep original if none)
776
829
  if selected_path:
@@ -828,9 +881,7 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
828
881
  import subprocess
829
882
 
830
883
  if shutil.which("fzf") is None:
831
- PrettyOutput.print(
832
- "未检测到 fzf,无法打开文件选择器。", OutputType.WARNING
833
- )
884
+ print("⚠️ 未检测到 fzf,无法打开文件选择器。")
834
885
  else:
835
886
  files = []
836
887
  try:
@@ -851,7 +902,7 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
851
902
  files = []
852
903
 
853
904
  if not files:
854
- PrettyOutput.print("未找到可选择的文件。", OutputType.INFO)
905
+ print("ℹ️ 未找到可选择的文件。")
855
906
  else:
856
907
  try:
857
908
  specials = [
@@ -895,7 +946,7 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
895
946
  if sel:
896
947
  selected_path = sel
897
948
  except Exception as e:
898
- PrettyOutput.print(f"FZF 执行失败: {e}", OutputType.ERROR)
949
+ print(f"FZF 执行失败: {e}")
899
950
 
900
951
  # Compute new text based on selection (or keep original if none)
901
952
  if selected_path:
@@ -949,5 +1000,5 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
949
1000
  continue
950
1001
  else:
951
1002
  if not user_input and print_on_empty:
952
- PrettyOutput.print("输入已取消", OutputType.INFO)
1003
+ print("ℹ️ 输入已取消")
953
1004
  return user_input