jarvis-ai-assistant 0.3.32__py3-none-any.whl → 0.3.34__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 CHANGED
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Jarvis AI Assistant"""
3
3
 
4
- __version__ = "0.3.32"
4
+ __version__ = "0.3.34"
@@ -439,6 +439,8 @@ class Agent:
439
439
  self.summary_prompt = cfg.summary_prompt or DEFAULT_SUMMARY_PROMPT
440
440
  self.max_token_count = int(cfg.max_token_count or get_max_token_count(model_group))
441
441
  self.force_save_memory = bool(cfg.force_save_memory)
442
+ # 非交互模式下自动完成标志需要同步到 Agent 实例,避免循环
443
+ self.auto_complete = bool(cfg.auto_complete)
442
444
 
443
445
  # 聚合配置到 AgentConfig,作为后续单一事实来源(保持兼容,不改变既有属性使用)
444
446
  self.config = cfg
@@ -12,9 +12,11 @@ from jarvis.jarvis_agent import (
12
12
  origin_agent_system_prompt,
13
13
  )
14
14
  from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
15
+ from jarvis.jarvis_agent.file_context_handler import file_context_handler
15
16
  from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
16
17
  from jarvis.jarvis_agent.task_manager import TaskManager
17
18
  from jarvis.jarvis_tools.registry import ToolRegistry
19
+ from jarvis.jarvis_utils.config import is_non_interactive
18
20
 
19
21
 
20
22
  class AgentManager:
@@ -46,7 +48,11 @@ class AgentManager:
46
48
  self.agent = Agent(
47
49
  system_prompt=origin_agent_system_prompt,
48
50
  model_group=self.model_group,
49
- input_handler=[shell_input_handler, builtin_input_handler],
51
+ input_handler=[
52
+ shell_input_handler,
53
+ file_context_handler,
54
+ builtin_input_handler,
55
+ ],
50
56
  output_handler=[ToolRegistry()], # type: ignore
51
57
  need_summary=False,
52
58
  use_methodology=self.use_methodology,
@@ -72,8 +78,8 @@ class AgentManager:
72
78
  self.agent.run(task_content)
73
79
  raise typer.Exit(code=0)
74
80
 
75
- # 处理预定义任务
76
- if self.agent.first:
81
+ # 处理预定义任务(非交互模式下跳过)
82
+ if not is_non_interactive() and self.agent.first:
77
83
  task_manager = TaskManager()
78
84
  tasks = task_manager.load_tasks()
79
85
  if tasks and (selected_task := task_manager.select_task(tasks)):
@@ -17,6 +17,7 @@ from jarvis.jarvis_utils.config import (
17
17
  is_force_save_memory,
18
18
  is_use_analysis,
19
19
  is_use_methodology,
20
+ is_non_interactive,
20
21
  )
21
22
 
22
23
 
@@ -30,6 +31,7 @@ class AgentConfig:
30
31
 
31
32
  # 运行行为
32
33
  auto_complete: bool = False
34
+ non_interactive: bool = False
33
35
  need_summary: bool = True
34
36
 
35
37
  # 可选配置(None 表示使用默认策略解析)
@@ -53,6 +55,7 @@ class AgentConfig:
53
55
  description=self.description,
54
56
  model_group=self.model_group,
55
57
  auto_complete=self.auto_complete,
58
+ non_interactive=self.non_interactive,
56
59
  need_summary=self.need_summary,
57
60
  summary_prompt=self.summary_prompt,
58
61
  execute_tool_confirm=self.execute_tool_confirm,
@@ -89,4 +92,8 @@ class AgentConfig:
89
92
  if cfg.force_save_memory is None:
90
93
  cfg.force_save_memory = is_force_save_memory()
91
94
 
95
+ # 非交互模式下默认开启自动完成
96
+ if is_non_interactive():
97
+ cfg.auto_complete = True
98
+
92
99
  return cfg
@@ -0,0 +1,69 @@
1
+ # -*- coding: utf-8 -*-
2
+ import re
3
+ import os
4
+ from typing import Any, Tuple
5
+
6
+ from jarvis.jarvis_tools.read_code import ReadCodeTool
7
+
8
+
9
+ def is_text_file(filepath: str) -> bool:
10
+ """
11
+ Check if a file is a text file.
12
+ """
13
+ try:
14
+ with open(filepath, "r", encoding="utf-8") as f:
15
+ f.read(1024) # Try to read a small chunk
16
+ return True
17
+ except (UnicodeDecodeError, IOError):
18
+ return False
19
+
20
+
21
+ def count_lines(filepath: str) -> int:
22
+ """
23
+ Count the number of lines in a file.
24
+ """
25
+ try:
26
+ with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
27
+ return sum(1 for _ in f)
28
+ except IOError:
29
+ return 0
30
+
31
+
32
+ def file_context_handler(user_input: str, agent_: Any) -> Tuple[str, bool]:
33
+ """
34
+ Extracts file paths from the input, reads their content if they are valid text files
35
+ and appends the content to the input.
36
+
37
+ Args:
38
+ user_input: The user's input string.
39
+ agent_: The agent instance.
40
+
41
+ Returns:
42
+ A tuple containing the modified user input and a boolean indicating if
43
+ further processing should be skipped.
44
+ """
45
+ # Regex to find paths in single quotes
46
+ file_paths = re.findall(r"'([^']+)'", user_input)
47
+
48
+ if not file_paths:
49
+ return user_input, False
50
+
51
+ added_context = ""
52
+ read_code_tool = ReadCodeTool()
53
+
54
+ for path in file_paths:
55
+ if os.path.isfile(path) and is_text_file(path):
56
+ line_count = count_lines(path)
57
+ if line_count > 0:
58
+ # Use ReadCodeTool to get formatted content
59
+ result = read_code_tool._handle_single_file(path)
60
+ if result["success"]:
61
+ # Remove the file path from the original input to avoid redundancy
62
+ user_input = user_input.replace(f"'{path}'", "")
63
+ # Append the full, formatted output from the tool, which includes headers and line numbers
64
+ added_context += "\n" + result["stdout"]
65
+
66
+ if added_context:
67
+ user_input = user_input.strip() + added_context
68
+
69
+ return user_input, False
@@ -19,6 +19,8 @@ from jarvis.jarvis_utils.config import (
19
19
  get_multi_agent_dirs,
20
20
  get_roles_dirs,
21
21
  get_data_dir,
22
+ set_config,
23
+ is_non_interactive,
22
24
  )
23
25
  import jarvis.jarvis_utils.utils as jutils
24
26
  from jarvis.jarvis_utils.input import user_confirm, get_single_line_input
@@ -30,6 +32,32 @@ import yaml # type: ignore
30
32
  from rich.table import Table
31
33
  from rich.console import Console
32
34
 
35
+ import sys
36
+
37
+
38
+ def _normalize_backup_data_argv(argv: List[str]) -> None:
39
+ """
40
+ 兼容旧版 Click/Typer 对可选参数的解析差异:
41
+ 若用户仅提供 --backup-data 而不跟参数,则在解析前注入默认目录。
42
+ """
43
+ try:
44
+ i = 0
45
+ while i < len(argv):
46
+ tok = argv[i]
47
+ if tok == "--backup-data":
48
+ # 情况1:位于末尾,无参数
49
+ # 情况2:后续是下一个选项(以 '-' 开头),表示未提供参数
50
+ if i == len(argv) - 1 or (i + 1 < len(argv) and argv[i + 1].startswith("-")):
51
+ argv.insert(i + 1, "~/jarvis_backups")
52
+ i += 1 # 跳过我们插入的默认值,避免重复插入
53
+ i += 1
54
+ except Exception:
55
+ # 静默忽略任何异常,避免影响主流程
56
+ pass
57
+
58
+
59
+ _normalize_backup_data_argv(sys.argv)
60
+
33
61
  app = typer.Typer(help="Jarvis AI 助手")
34
62
 
35
63
 
@@ -187,9 +215,9 @@ def handle_interactive_config_option(
187
215
  return True
188
216
 
189
217
 
190
- def handle_backup_option(backup: bool) -> bool:
218
+ def handle_backup_option(backup_dir_path: Optional[str]) -> bool:
191
219
  """处理数据备份选项,返回是否已处理并需提前结束。"""
192
- if not backup:
220
+ if backup_dir_path is None:
193
221
  return False
194
222
 
195
223
  init_env("", config_file=None)
@@ -198,7 +226,8 @@ def handle_backup_option(backup: bool) -> bool:
198
226
  PrettyOutput.print(f"数据目录不存在: {data_dir}", OutputType.ERROR)
199
227
  return True
200
228
 
201
- backup_dir = Path(os.path.expanduser("~/jarvis_backups"))
229
+ backup_dir_str = backup_dir_path if backup_dir_path.strip() else "~/jarvis_backups"
230
+ backup_dir = Path(os.path.expanduser(backup_dir_str))
202
231
  backup_dir.mkdir(exist_ok=True)
203
232
 
204
233
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
@@ -215,18 +244,37 @@ def handle_backup_option(backup: bool) -> bool:
215
244
  return True
216
245
 
217
246
 
218
- def handle_restore_option(restore_path: Optional[str]) -> bool:
247
+ def handle_restore_option(restore_path: Optional[str], config_file: Optional[str]) -> bool:
219
248
  """处理数据恢复选项,返回是否已处理并需提前结束。"""
220
249
  if not restore_path:
221
250
  return False
222
251
 
223
- restore_file = Path(restore_path)
252
+ restore_file = Path(os.path.expanduser(os.path.expandvars(restore_path)))
253
+ # 兼容 ~ 与环境变量,避免用户输入未展开路径导致找不到文件
224
254
  if not restore_file.is_file():
225
- PrettyOutput.print(f"指定的恢复文件不存在: {restore_path}", OutputType.ERROR)
255
+ PrettyOutput.print(f"指定的恢复文件不存在: {restore_file}", OutputType.ERROR)
226
256
  return True
227
257
 
228
- init_env("", config_file=None)
229
- data_dir = Path(get_data_dir())
258
+ # 在恢复数据时不要触发完整环境初始化,避免引导流程或网络请求
259
+ # 优先从配置文件解析 JARVIS_DATA_PATH,否则回退到默认数据目录
260
+ data_dir_str: Optional[str] = None
261
+ try:
262
+ if config_file:
263
+ cfg_path = Path(os.path.expanduser(os.path.expandvars(config_file)))
264
+ if cfg_path.is_file():
265
+ with open(cfg_path, "r", encoding="utf-8", errors="ignore") as cf:
266
+ cfg_data = yaml.safe_load(cf) or {}
267
+ if isinstance(cfg_data, dict):
268
+ val = cfg_data.get("JARVIS_DATA_PATH")
269
+ if isinstance(val, str) and val.strip():
270
+ data_dir_str = val.strip()
271
+ except Exception:
272
+ data_dir_str = None
273
+
274
+ if not data_dir_str:
275
+ data_dir_str = get_data_dir()
276
+
277
+ data_dir = Path(os.path.expanduser(os.path.expandvars(str(data_dir_str))))
230
278
 
231
279
  if data_dir.exists():
232
280
  if not user_confirm(
@@ -271,6 +319,9 @@ def try_switch_to_jca_if_git_repo(
271
319
  task: Optional[str],
272
320
  ) -> None:
273
321
  """在初始化环境前检测Git仓库,并可选择自动切换到代码开发模式(jca)。"""
322
+ # 非交互模式下跳过代码模式切换提示与相关输出
323
+ if is_non_interactive():
324
+ return
274
325
  if is_enable_git_repo_jca_switch():
275
326
  try:
276
327
  res = subprocess.run(
@@ -443,6 +494,20 @@ def handle_builtin_config_selector(
443
494
  )
444
495
 
445
496
  if options:
497
+ # Add a default option to skip selection
498
+ options.insert(
499
+ 0,
500
+ {
501
+ "category": "skip",
502
+ "cmd": "",
503
+ "file": "",
504
+ "name": "跳过选择 (使用默认通用代理)",
505
+ "desc": "直接按回车或ESC也可跳过",
506
+ "details": "",
507
+ "roles_count": 0,
508
+ },
509
+ )
510
+
446
511
  PrettyOutput.section("可用的内置配置", OutputType.SUCCESS)
447
512
  # 使用 rich Table 呈现
448
513
  table = Table(show_header=True, header_style="bold magenta")
@@ -511,35 +576,44 @@ def handle_builtin_config_selector(
511
576
  if choice_index != -1:
512
577
  try:
513
578
  sel = options[choice_index]
514
- args: List[str] = []
515
-
516
- if sel["category"] == "agent":
517
- # jarvis-agent 支持 -f/--config(全局配置)与 -c/--agent-definition
518
- args = [str(sel["cmd"]), "-c", str(sel["file"])]
519
- if model_group:
520
- args += ["-g", str(model_group)]
521
- if config_file:
522
- args += ["-f", str(config_file)]
523
- if task:
524
- args += ["--task", str(task)]
525
-
526
- elif sel["category"] == "multi_agent":
527
- # jarvis-multi-agent 需要 -c/--config,用户输入通过 -i/--input 传递
528
- args = [str(sel["cmd"]), "-c", str(sel["file"])]
529
- if task:
530
- args += ["-i", str(task)]
531
-
532
- elif sel["category"] == "roles":
533
- # jarvis-platform-manager role 子命令,支持 -c/-t/-g
534
- args = [str(sel["cmd"]), "role", "-c", str(sel["file"])]
535
- if model_group:
536
- args += ["-g", str(model_group)]
537
-
538
- if args:
539
- PrettyOutput.print(
540
- f"正在启动: {' '.join(args)}", OutputType.INFO
541
- )
542
- os.execvp(args[0], args)
579
+ # If the "skip" option is chosen, do nothing and proceed to default agent
580
+ if sel["category"] == "skip":
581
+ pass
582
+ else:
583
+ args: List[str] = []
584
+
585
+ if sel["category"] == "agent":
586
+ # jarvis-agent 支持 -f/--config(全局配置)与 -c/--agent-definition
587
+ args = [str(sel["cmd"]), "-c", str(sel["file"])]
588
+ if model_group:
589
+ args += ["-g", str(model_group)]
590
+ if config_file:
591
+ args += ["-f", str(config_file)]
592
+ if task:
593
+ args += ["--task", str(task)]
594
+
595
+ elif sel["category"] == "multi_agent":
596
+ # jarvis-multi-agent 需要 -c/--config,用户输入通过 -i/--input 传递
597
+ args = [str(sel["cmd"]), "-c", str(sel["file"])]
598
+ if task:
599
+ args += ["-i", str(task)]
600
+
601
+ elif sel["category"] == "roles":
602
+ # jarvis-platform-manager role 子命令,支持 -c/-t/-g
603
+ args = [
604
+ str(sel["cmd"]),
605
+ "role",
606
+ "-c",
607
+ str(sel["file"]),
608
+ ]
609
+ if model_group:
610
+ args += ["-g", str(model_group)]
611
+
612
+ if args:
613
+ PrettyOutput.print(
614
+ f"正在启动: {' '.join(args)}", OutputType.INFO
615
+ )
616
+ os.execvp(args[0], args)
543
617
  except Exception:
544
618
  # 任何异常都不影响默认流程
545
619
  pass
@@ -590,12 +664,19 @@ def run_cli(
590
664
  "--disable-methodology-analysis",
591
665
  help="禁用方法论和任务分析(覆盖配置文件设置)",
592
666
  ),
593
- backup_data: bool = typer.Option(
594
- False, "--backup-data", help="备份 Jarvis 数据目录 (~/.jarvis)"
667
+ backup_data: Optional[str] = typer.Option(
668
+ None,
669
+ "--backup-data",
670
+ help="备份 Jarvis 数据目录. 可选地传入备份目录. 默认为 '~/jarvis_backups'",
671
+ show_default=False,
672
+ flag_value="~/jarvis_backups",
595
673
  ),
596
674
  restore_data: Optional[str] = typer.Option(
597
675
  None, "--restore-data", help="从指定的压缩包恢复 Jarvis 数据"
598
676
  ),
677
+ non_interactive: bool = typer.Option(
678
+ False, "-n", "--non-interactive", help="启用非交互模式:用户无法与命令交互,脚本执行超时限制为5分钟"
679
+ ),
599
680
  ) -> None:
600
681
  """Jarvis AI assistant command-line interface."""
601
682
  if ctx.invoked_subcommand is not None:
@@ -604,12 +685,43 @@ def run_cli(
604
685
  # 使用 rich 输出命令与快捷方式总览
605
686
  print_commands_overview()
606
687
 
688
+ # CLI 标志:非交互模式(不依赖配置文件)
689
+ if non_interactive:
690
+ try:
691
+ os.environ["JARVIS_NON_INTERACTIVE"] = "true"
692
+ except Exception:
693
+ pass
694
+ # 注意:全局配置同步在 init_env 之后执行,避免被覆盖
695
+
696
+ # 同步其他 CLI 选项到全局配置,确保后续模块读取一致
697
+ try:
698
+ if model_group:
699
+ set_config("JARVIS_LLM_GROUP", str(model_group))
700
+ if tool_group:
701
+ set_config("JARVIS_TOOL_GROUP", str(tool_group))
702
+ if disable_methodology_analysis:
703
+ set_config("JARVIS_USE_METHODOLOGY", False)
704
+ set_config("JARVIS_USE_ANALYSIS", False)
705
+ if restore_session:
706
+ set_config("JARVIS_RESTORE_SESSION", True)
707
+ except Exception:
708
+ # 静默忽略同步异常,不影响主流程
709
+ pass
710
+
711
+ # 非交互模式要求从命令行传入任务
712
+ if non_interactive and not (task and str(task).strip()):
713
+ PrettyOutput.print(
714
+ "非交互模式已启用:必须使用 --task 传入任务内容,因多行输入不可用。",
715
+ OutputType.ERROR,
716
+ )
717
+ raise typer.Exit(code=2)
718
+
607
719
  # 处理数据备份
608
720
  if handle_backup_option(backup_data):
609
721
  return
610
722
 
611
723
  # 处理数据恢复
612
- if handle_restore_option(restore_data):
724
+ if handle_restore_option(restore_data, config_file):
613
725
  return
614
726
 
615
727
  # 处理配置文件编辑
@@ -632,18 +744,39 @@ def run_cli(
632
744
  preload_config_for_flags(config_file)
633
745
 
634
746
  # 在初始化环境前检测Git仓库,并可选择自动切换到代码开发模式(jca)
635
- try_switch_to_jca_if_git_repo(
636
- model_group, tool_group, config_file, restore_session, task
637
- )
747
+ if not non_interactive:
748
+ try_switch_to_jca_if_git_repo(
749
+ model_group, tool_group, config_file, restore_session, task
750
+ )
638
751
 
639
752
  # 在进入默认通用代理前,列出内置配置供选择(agent/multi_agent/roles)
640
- handle_builtin_config_selector(model_group, tool_group, config_file, task)
753
+ # 非交互模式下跳过内置角色/配置选择
754
+ if not non_interactive:
755
+ handle_builtin_config_selector(model_group, tool_group, config_file, task)
641
756
 
642
757
  # 初始化环境
643
758
  init_env(
644
759
  "欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!", config_file=config_file
645
760
  )
646
761
 
762
+ # 在初始化环境后同步 CLI 选项到全局配置,避免被 init_env 覆盖
763
+ try:
764
+ if model_group:
765
+ set_config("JARVIS_LLM_GROUP", str(model_group))
766
+ if tool_group:
767
+ set_config("JARVIS_TOOL_GROUP", str(tool_group))
768
+ if disable_methodology_analysis:
769
+ set_config("JARVIS_USE_METHODOLOGY", False)
770
+ set_config("JARVIS_USE_ANALYSIS", False)
771
+ if restore_session:
772
+ set_config("JARVIS_RESTORE_SESSION", True)
773
+ if non_interactive:
774
+ # 保持运行期非交互标志
775
+ set_config("JARVIS_NON_INTERACTIVE", True)
776
+ except Exception:
777
+ # 静默忽略同步异常,不影响主流程
778
+ pass
779
+
647
780
  # 运行主流程
648
781
  try:
649
782
  agent_manager = AgentManager(
@@ -9,6 +9,7 @@ from jarvis.jarvis_agent import Agent
9
9
  from jarvis.jarvis_utils.input import get_multiline_input
10
10
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
11
11
  from jarvis.jarvis_utils.utils import init_env
12
+ from jarvis.jarvis_utils.config import set_config
12
13
 
13
14
  app = typer.Typer(help="Jarvis AI 助手")
14
15
 
@@ -46,16 +47,45 @@ def cli(
46
47
  None, "-c", "--agent-definition", help="代理定义文件路径"
47
48
  ),
48
49
  task: Optional[str] = typer.Option(None, "-T", "--task", help="初始任务内容"),
49
-
50
+
50
51
  model_group: Optional[str] = typer.Option(
51
52
  None, "-g", "--llm-group", help="使用的模型组,覆盖配置文件中的设置"
52
53
  ),
54
+ non_interactive: bool = typer.Option(
55
+ False, "-n", "--non-interactive", help="启用非交互模式:用户无法与命令交互,脚本执行超时限制为5分钟"
56
+ ),
53
57
  ):
54
58
  """Main entry point for Jarvis agent"""
55
- # Initialize environment
59
+ # CLI 标志:非交互模式(不依赖配置文件)
60
+ if non_interactive:
61
+ try:
62
+ os.environ["JARVIS_NON_INTERACTIVE"] = "true"
63
+ except Exception:
64
+ pass
65
+ try:
66
+ set_config("JARVIS_NON_INTERACTIVE", True)
67
+ except Exception:
68
+ pass
69
+ # 非交互模式要求从命令行传入任务
70
+ if non_interactive and not (task and str(task).strip()):
71
+ PrettyOutput.print(
72
+ "非交互模式已启用:必须使用 --task 传入任务内容,因多行输入不可用。",
73
+ OutputType.ERROR,
74
+ )
75
+ raise typer.Exit(code=2)
76
+ # Initialize环境
56
77
  init_env(
57
78
  "欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!", config_file=config_file
58
79
  )
80
+ # 在初始化环境后同步 CLI 选项到全局配置,避免被 init_env 覆盖
81
+ try:
82
+ if model_group:
83
+ set_config("JARVIS_LLM_GROUP", str(model_group))
84
+ if non_interactive:
85
+ set_config("JARVIS_NON_INTERACTIVE", True)
86
+ except Exception:
87
+ # 静默忽略同步异常,不影响主流程
88
+ pass
59
89
 
60
90
  # Load configuration
61
91
  config = load_config(agent_definition) if agent_definition else {}
@@ -7,6 +7,7 @@ AgentRunLoop: 承载 Agent 的主运行循环逻辑。
7
7
  - 暂不变更外部调用入口,后续在 Agent._main_loop 中委派到该类
8
8
  - 保持与现有异常处理、工具调用、用户交互完全一致
9
9
  """
10
+ import os
10
11
  from enum import Enum
11
12
  from typing import Any, TYPE_CHECKING
12
13
 
@@ -22,6 +23,8 @@ if TYPE_CHECKING:
22
23
  class AgentRunLoop:
23
24
  def __init__(self, agent: "Agent") -> None:
24
25
  self.agent = agent
26
+ self.conversation_rounds = 0
27
+ self.tool_reminder_rounds = int(os.environ.get("JARVIS_TOOL_REMINDER_ROUNDS", 20))
25
28
 
26
29
  def run(self) -> Any:
27
30
  """主运行循环(委派到传入的 agent 实例的方法与属性)"""
@@ -29,6 +32,12 @@ class AgentRunLoop:
29
32
 
30
33
  while True:
31
34
  try:
35
+ self.conversation_rounds += 1
36
+ if self.conversation_rounds % self.tool_reminder_rounds == 0:
37
+ self.agent.session.addon_prompt = join_prompts(
38
+ [self.agent.session.addon_prompt, self.agent.get_tool_usage_prompt()]
39
+ )
40
+
32
41
  ag = self.agent
33
42
 
34
43
  # 更新输入处理器标志
@@ -14,6 +14,7 @@ import typer
14
14
  from jarvis.jarvis_agent import Agent
15
15
  from jarvis.jarvis_agent.events import AFTER_TOOL_CALL
16
16
  from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
17
+ from jarvis.jarvis_agent.file_context_handler import file_context_handler
17
18
  from jarvis.jarvis_agent.edit_file_handler import EditFileHandler
18
19
  from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
19
20
  from jarvis.jarvis_code_agent.lint import get_lint_tools
@@ -23,6 +24,7 @@ from jarvis.jarvis_utils.config import (
23
24
  is_confirm_before_apply_patch,
24
25
  is_enable_static_analysis,
25
26
  get_git_check_mode,
27
+ set_config,
26
28
  )
27
29
  from jarvis.jarvis_utils.git_utils import (
28
30
  confirm_add_new_files,
@@ -89,7 +91,11 @@ class CodeAgent:
89
91
  auto_complete=False,
90
92
  output_handler=[tool_registry, EditFileHandler()], # type: ignore
91
93
  model_group=model_group,
92
- input_handler=[shell_input_handler, builtin_input_handler],
94
+ input_handler=[
95
+ shell_input_handler,
96
+ file_context_handler,
97
+ builtin_input_handler,
98
+ ],
93
99
  need_summary=need_summary,
94
100
  use_methodology=False, # 禁用方法论
95
101
  use_analysis=False, # 禁用分析
@@ -770,7 +776,6 @@ class CodeAgent:
770
776
 
771
777
  @app.command()
772
778
  def cli(
773
-
774
779
  model_group: Optional[str] = typer.Option(
775
780
  None, "-g", "--llm-group", help="使用的模型组,覆盖配置文件中的设置"
776
781
  ),
@@ -801,13 +806,44 @@ def cli(
801
806
  "--suffix",
802
807
  help="提交信息后缀(用换行分隔)",
803
808
  ),
809
+ non_interactive: bool = typer.Option(
810
+ False, "-n", "--non-interactive", help="启用非交互模式:用户无法与命令交互,脚本执行超时限制为5分钟"
811
+ ),
804
812
  ) -> None:
805
813
  """Jarvis主入口点。"""
814
+ # CLI 标志:非交互模式(不依赖配置文件)
815
+ if non_interactive:
816
+ try:
817
+ os.environ["JARVIS_NON_INTERACTIVE"] = "true"
818
+ except Exception:
819
+ pass
820
+ # 注意:全局配置同步放在 init_env 之后执行,避免被 init_env 覆盖
821
+ # 非交互模式要求从命令行传入任务
822
+ if non_interactive and not (requirement and str(requirement).strip()):
823
+ PrettyOutput.print(
824
+ "非交互模式已启用:必须使用 --requirement 传入任务内容,因多行输入不可用。",
825
+ OutputType.ERROR,
826
+ )
827
+ raise typer.Exit(code=2)
806
828
  init_env(
807
829
  "欢迎使用 Jarvis-CodeAgent,您的代码工程助手已准备就绪!",
808
830
  config_file=config_file,
809
831
  )
810
832
 
833
+ # 在初始化环境后同步 CLI 选项到全局配置,避免被 init_env 覆盖
834
+ try:
835
+ if model_group:
836
+ set_config("JARVIS_LLM_GROUP", str(model_group))
837
+ if tool_group:
838
+ set_config("JARVIS_TOOL_GROUP", str(tool_group))
839
+ if restore_session:
840
+ set_config("JARVIS_RESTORE_SESSION", True)
841
+ if non_interactive:
842
+ set_config("JARVIS_NON_INTERACTIVE", True)
843
+ except Exception:
844
+ # 静默忽略同步异常,不影响主流程
845
+ pass
846
+
811
847
  try:
812
848
  subprocess.run(
813
849
  ["git", "rev-parse", "--git-dir"],
@@ -188,6 +188,11 @@
188
188
  "description": "AI工具筛选阈值:当可用工具数量超过此值时触发AI筛选",
189
189
  "default": 30
190
190
  },
191
+ "JARVIS_SCRIPT_EXECUTION_TIMEOUT": {
192
+ "type": "number",
193
+ "description": "脚本执行的超时时间(秒),仅在非交互模式下生效。",
194
+ "default": 300
195
+ },
191
196
  "JARVIS_CONFIRM_BEFORE_APPLY_PATCH": {
192
197
  "type": "boolean",
193
198
  "description": "应用补丁前是否需要确认",
@@ -312,6 +317,11 @@
312
317
  "description": "是否启用立即中断:在对话迭代中检测到中断信号时立即返回",
313
318
  "default": false
314
319
  },
320
+ "JARVIS_SAVE_SESSION_HISTORY": {
321
+ "type": "boolean",
322
+ "description": "是否保存会话记录",
323
+ "default": false
324
+ },
315
325
  "JARVIS_GIT_CHECK_MODE": {
316
326
  "type": "string",
317
327
  "enum": ["strict", "warn"],
@@ -154,9 +154,30 @@ content: |2
154
154
  PrettyOutput.print(f"未知消息类型: {type(msg)}", OutputType.WARNING)
155
155
  break
156
156
 
157
+ # Generate a brief summary via direct model call to avoid run-loop recursion
158
+ try:
159
+ # 参照 Agent.generate_summary 的实现思路:基于当前 session.prompt 追加请求提示,直接调用底层模型
160
+ multi_agent_summary_prompt = """
161
+ 请基于当前会话,为即将发送给其他智能体的协作交接写一段摘要,包含:
162
+ - 已完成的主要工作与产出
163
+ - 关键决策及其理由
164
+ - 已知的约束/风险/边界条件
165
+ - 未解决的问题与待澄清点
166
+ - 下一步建议与对目标智能体的具体请求
167
+ 要求:
168
+ - 仅输出纯文本,不包含任何指令或工具调用
169
+ - 使用简洁的要点式表述
170
+ """.strip()
171
+ summary_any: Any = agent.model.chat_until_success( # type: ignore[attr-defined]
172
+ f"{agent.session.prompt}\n{multi_agent_summary_prompt}"
173
+ )
174
+ summary_text = summary_any.strip() if isinstance(summary_any, str) else ""
175
+ except Exception:
176
+ summary_text = ""
157
177
  prompt = f"""
158
178
  Please handle this message:
159
179
  from: {last_agent_name}
180
+ summary_of_sender_work: {summary_text}
160
181
  content: {msg['content']}
161
182
  """
162
183
  to_agent_name = msg.get("to")
@@ -3,10 +3,12 @@ from typing import Optional
3
3
 
4
4
  import typer
5
5
  import yaml # type: ignore[import-untyped]
6
+ import os
6
7
 
7
8
  from jarvis.jarvis_multi_agent import MultiAgent
8
9
  from jarvis.jarvis_utils.input import get_multiline_input
9
10
  from jarvis.jarvis_utils.utils import init_env
11
+ from jarvis.jarvis_utils.config import set_config
10
12
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
11
13
 
12
14
  app = typer.Typer(help="多智能体系统启动器")
@@ -18,9 +20,35 @@ def cli(
18
20
  user_input: Optional[str] = typer.Option(
19
21
  None, "--input", "-i", help="用户输入(可选)"
20
22
  ),
23
+ non_interactive: bool = typer.Option(
24
+ False, "-n", "--non-interactive", help="启用非交互模式:用户无法与命令交互,脚本执行超时限制为5分钟"
25
+ ),
26
+ ),
21
27
  ):
22
28
  """从YAML配置文件初始化并运行多智能体系统"""
29
+ # CLI 标志:非交互模式(不依赖配置文件)
30
+ if non_interactive:
31
+ try:
32
+ os.environ["JARVIS_NON_INTERACTIVE"] = "true"
33
+ except Exception:
34
+ pass
35
+ # 注意:全局配置同步在 init_env 之后执行,避免被覆盖
36
+ # 非交互模式要求从命令行传入任务
37
+ if non_interactive and not (user_input and str(user_input).strip()):
38
+ PrettyOutput.print(
39
+ "非交互模式已启用:必须使用 --input 传入任务内容,因多行输入不可用。",
40
+ OutputType.ERROR,
41
+ )
42
+ raise typer.Exit(code=2)
23
43
  init_env("欢迎使用 Jarvis-MultiAgent,您的多智能体系统已准备就绪!")
44
+
45
+ # 在初始化环境后同步 CLI 选项到全局配置,避免被 init_env 覆盖
46
+ try:
47
+ if non_interactive:
48
+ set_config("JARVIS_NON_INTERACTIVE", True)
49
+ except Exception:
50
+ # 静默忽略同步异常,不影响主流程
51
+ pass
24
52
 
25
53
  try:
26
54
  with open(config, "r", errors="ignore") as f:
@@ -1,5 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  import re
3
+ import os
4
+ from datetime import datetime
3
5
  from abc import ABC, abstractmethod
4
6
  from types import TracebackType
5
7
  from typing import Dict, Generator, List, Optional, Tuple, Type
@@ -17,6 +19,8 @@ from jarvis.jarvis_utils.config import (
17
19
  get_pretty_output,
18
20
  is_print_prompt,
19
21
  is_immediate_abort,
22
+ is_save_session_history,
23
+ get_data_dir,
20
24
  )
21
25
  from jarvis.jarvis_utils.embedding import split_text_into_chunks
22
26
  from jarvis.jarvis_utils.globals import set_in_chat, get_interrupt, console
@@ -34,6 +38,7 @@ class BasePlatform(ABC):
34
38
  self.web = False # 添加web属性,默认false
35
39
  self._saved = False
36
40
  self.model_group: Optional[str] = None
41
+ self._session_history_file: Optional[str] = None
37
42
 
38
43
  def __enter__(self) -> Self:
39
44
  """Enter context manager"""
@@ -57,6 +62,7 @@ class BasePlatform(ABC):
57
62
  def reset(self):
58
63
  """Reset model"""
59
64
  self.delete_chat()
65
+ self._session_history_file = None
60
66
 
61
67
  @abstractmethod
62
68
  def chat(self, message: str) -> Generator[str, None, None]:
@@ -135,6 +141,7 @@ class BasePlatform(ABC):
135
141
  if first_chunk:
136
142
  break
137
143
  except StopIteration:
144
+ self._append_session_history(message, "")
138
145
  return ""
139
146
 
140
147
  text_content = Text(overflow="fold")
@@ -200,6 +207,7 @@ class BasePlatform(ABC):
200
207
  live.update(panel)
201
208
 
202
209
  if is_immediate_abort() and get_interrupt():
210
+ self._append_session_history(message, response)
203
211
  return response # Return the partial response immediately
204
212
 
205
213
  # Ensure any remaining content in the buffer is displayed
@@ -225,6 +233,7 @@ class BasePlatform(ABC):
225
233
  console.print(s, end="")
226
234
  response += s
227
235
  if is_immediate_abort() and get_interrupt():
236
+ self._append_session_history(message, response)
228
237
  return response
229
238
  console.print()
230
239
  end_time = time.time()
@@ -234,6 +243,7 @@ class BasePlatform(ABC):
234
243
  for s in self.chat(message):
235
244
  response += s
236
245
  if is_immediate_abort() and get_interrupt():
246
+ self._append_session_history(message, response)
237
247
  return response
238
248
  # Keep original think tag handling
239
249
  response = re.sub(
@@ -242,6 +252,8 @@ class BasePlatform(ABC):
242
252
  response = re.sub(
243
253
  ot("thinking") + r".*?" + ct("thinking"), "", response, flags=re.DOTALL
244
254
  )
255
+ # Save session history (input and full response)
256
+ self._append_session_history(message, response)
245
257
  return response
246
258
 
247
259
  def chat_until_success(self, message: str) -> str:
@@ -346,6 +358,51 @@ class BasePlatform(ABC):
346
358
  """Set web flag"""
347
359
  self.web = web
348
360
 
361
+ def _append_session_history(self, user_input: str, model_output: str) -> None:
362
+ """
363
+ Append the user input and model output to a session history file if enabled.
364
+ The file name is generated on first save and reused until reset.
365
+ """
366
+ try:
367
+ if not is_save_session_history():
368
+ return
369
+
370
+ if self._session_history_file is None:
371
+ # Ensure data directory exists
372
+ data_dir = get_data_dir()
373
+ os.makedirs(data_dir, exist_ok=True)
374
+
375
+ # Build a safe filename including platform, model and timestamp
376
+ try:
377
+ platform_name = type(self).platform_name()
378
+ except Exception:
379
+ platform_name = "unknown_platform"
380
+
381
+ try:
382
+ model_name = self.name()
383
+ except Exception:
384
+ model_name = "unknown_model"
385
+
386
+ safe_platform = re.sub(r"[^\w\-\.]+", "_", str(platform_name))
387
+ safe_model = re.sub(r"[^\w\-\.]+", "_", str(model_name))
388
+ ts = datetime.now().strftime("%Y%m%d_%H%M%S")
389
+
390
+ self._session_history_file = os.path.join(
391
+ data_dir, f"session_history_{safe_platform}_{safe_model}_{ts}.log"
392
+ )
393
+
394
+ # Append record
395
+ with open(self._session_history_file, "a", encoding="utf-8", errors="ignore") as f:
396
+ ts_line = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
397
+ f.write(f"===== {ts_line} =====\n")
398
+ f.write("USER:\n")
399
+ f.write(f"{user_input}\n")
400
+ f.write("\nASSISTANT:\n")
401
+ f.write(f"{model_output}\n\n")
402
+ except Exception:
403
+ # Do not break chat flow if writing history fails
404
+ pass
405
+
349
406
  @abstractmethod
350
407
  def support_web(self) -> bool:
351
408
  """Check if platform supports web functionality"""
@@ -19,6 +19,7 @@ class ScriptTool:
19
19
  + "注意:由于模型上下文长度限制,请避免在脚本中输出大量信息,应该使用rg过滤输出。"
20
20
  + "与virtual_tty不同,此工具会创建一个临时的脚本文件,并使用脚本命令执行脚本,不具备交互式操作的能力,"
21
21
  + "适用于需要执行脚本并获取结果的场景。不适合需要交互式操作的场景(如:ssh连接、sftp传输、gdb/dlv调试等)。"
22
+ + "在非交互模式(JARVIS_NON_INTERACTIVE=true)下:脚本执行时间限制为5分钟,超时将被终止并返回超时信息;用户无法与命令交互,请不要执行需要交互的命令。"
22
23
  )
23
24
  parameters = {
24
25
  "type": "object",
@@ -115,8 +116,37 @@ class ScriptTool:
115
116
  f"script -q -c '{interpreter} {script_path}' {output_file}"
116
117
  )
117
118
 
118
- # Execute command and capture return code
119
- os.system(tee_command)
119
+ # Execute command with optional timeout in non-interactive mode
120
+ from jarvis.jarvis_utils.config import get_script_execution_timeout, is_non_interactive
121
+ import subprocess
122
+
123
+ timed_out = False
124
+ if is_non_interactive():
125
+ try:
126
+ proc = subprocess.Popen(tee_command, shell=True)
127
+ try:
128
+ proc.wait(timeout=get_script_execution_timeout())
129
+ except subprocess.TimeoutExpired:
130
+ timed_out = True
131
+ try:
132
+ proc.kill()
133
+ except Exception:
134
+ pass
135
+ except Exception as e:
136
+ PrettyOutput.print(str(e), OutputType.ERROR)
137
+ # Attempt to read any partial output if available
138
+ try:
139
+ output = self.get_display_output(output_file)
140
+ except Exception as ee:
141
+ output = f"读取输出文件失败: {str(ee)}"
142
+ return {
143
+ "success": False,
144
+ "stdout": output,
145
+ "stderr": f"执行脚本失败: {str(e)}",
146
+ }
147
+ else:
148
+ # Execute command and capture return code
149
+ os.system(tee_command)
120
150
 
121
151
  # Read and process output file
122
152
  try:
@@ -125,12 +155,19 @@ class ScriptTool:
125
155
  except Exception as e:
126
156
  output = f"读取输出文件失败: {str(e)}"
127
157
 
128
- # Return successful result
129
- return {
130
- "success": True,
131
- "stdout": output,
132
- "stderr": "",
133
- }
158
+ # Return result (handle timeout in non-interactive mode)
159
+ if is_non_interactive() and timed_out:
160
+ return {
161
+ "success": False,
162
+ "stdout": output,
163
+ "stderr": f"执行超时(超过{get_script_execution_timeout()}秒),进程已被终止(非交互模式)。",
164
+ }
165
+ else:
166
+ return {
167
+ "success": True,
168
+ "stdout": output,
169
+ "stderr": "",
170
+ }
134
171
 
135
172
  finally:
136
173
  # Clean up temporary files
@@ -58,7 +58,8 @@ class WebpageTool:
58
58
  2. 包含网页标题
59
59
  3. 根据用户需求提供准确、完整的信息"""
60
60
  response = model.chat_until_success(prompt) # type: ignore
61
- return {"success": True, "stdout": response, "stderr": ""}
61
+ if response and response.strip():
62
+ return {"success": True, "stdout": response, "stderr": ""}
62
63
 
63
64
  # 2) 然后尝试使用默认平台(normal)的 web 能力
64
65
  model = PlatformRegistry().get_normal_platform()
@@ -73,7 +74,8 @@ class WebpageTool:
73
74
  2. 包含网页标题
74
75
  3. 根据用户需求提供准确、完整的信息"""
75
76
  response = model.chat_until_success(prompt) # type: ignore
76
- return {"success": True, "stdout": response, "stderr": ""}
77
+ if response and response.strip():
78
+ return {"success": True, "stdout": response, "stderr": ""}
77
79
 
78
80
  # 3) 回退:使用 requests 抓取网页,再用模型分析
79
81
 
@@ -147,11 +147,13 @@ class SearchWebTool:
147
147
  if model.support_web():
148
148
  model.set_web(True)
149
149
  model.set_suppress_output(False)
150
- return {
151
- "stdout": model.chat_until_success(query),
152
- "stderr": "",
153
- "success": True,
154
- }
150
+ response = model.chat_until_success(query)
151
+ if response and response.strip():
152
+ return {
153
+ "stdout": response,
154
+ "stderr": "",
155
+ "success": True,
156
+ }
155
157
 
156
158
  # 否则使用现有的模型选择流程
157
159
  if agent.model.support_web():
@@ -161,11 +163,13 @@ class SearchWebTool:
161
163
  model.set_model_name(agent.model.name())
162
164
  model.set_web(True)
163
165
  model.set_suppress_output(False)
164
- return {
165
- "stdout": model.chat_until_success(query),
166
- "stderr": "",
167
- "success": True,
168
- }
166
+ response = model.chat_until_success(query)
167
+ if response and response.strip():
168
+ return {
169
+ "stdout": response,
170
+ "stderr": "",
171
+ "success": True,
172
+ }
169
173
 
170
174
  return self._search_with_ddgs(query, agent)
171
175
 
@@ -712,6 +712,16 @@ def get_tool_filter_threshold() -> int:
712
712
  return int(GLOBAL_CONFIG_DATA.get("JARVIS_TOOL_FILTER_THRESHOLD", 30))
713
713
 
714
714
 
715
+ def get_script_execution_timeout() -> int:
716
+ """
717
+ 获取脚本执行的超时时间(秒)。
718
+
719
+ 返回:
720
+ int: 超时时间,默认为300秒(5分钟)
721
+ """
722
+ return int(GLOBAL_CONFIG_DATA.get("JARVIS_SCRIPT_EXECUTION_TIMEOUT", 300))
723
+
724
+
715
725
  def is_enable_git_repo_jca_switch() -> bool:
716
726
  """
717
727
  是否启用:在初始化环境前检测Git仓库并提示可切换到代码开发模式(jca)
@@ -730,9 +740,42 @@ def is_enable_builtin_config_selector() -> bool:
730
740
  )
731
741
 
732
742
 
743
+ def is_save_session_history() -> bool:
744
+ """
745
+ 是否保存会话记录。
746
+
747
+ 返回:
748
+ bool: 如果要保存会话记录则返回True, 默认为False
749
+ """
750
+ return GLOBAL_CONFIG_DATA.get("JARVIS_SAVE_SESSION_HISTORY", False) is True
751
+
752
+
733
753
  def is_immediate_abort() -> bool:
734
754
  """
735
755
  是否启用立即中断:当在对话过程中检测到用户中断信号时,立即停止输出并返回。
736
756
  默认关闭
737
757
  """
738
758
  return GLOBAL_CONFIG_DATA.get("JARVIS_IMMEDIATE_ABORT", False) is True
759
+
760
+
761
+ def is_non_interactive() -> bool:
762
+ """
763
+ 获取是否启用非交互模式。
764
+
765
+ 返回:
766
+ bool: 如果启用非交互模式则返回True,默认为False
767
+ """
768
+ # 优先读取环境变量,确保 CLI 标志生效且不被配置覆盖
769
+ try:
770
+ import os
771
+ v = os.getenv("JARVIS_NON_INTERACTIVE")
772
+ if v is not None:
773
+ val = str(v).strip().lower()
774
+ if val in ("1", "true", "yes", "on"):
775
+ return True
776
+ if val in ("0", "false", "no", "off"):
777
+ return False
778
+ except Exception:
779
+ # 忽略环境变量解析异常,回退到配置
780
+ pass
781
+ return GLOBAL_CONFIG_DATA.get("JARVIS_NON_INTERACTIVE", False) is True
@@ -366,6 +366,9 @@ class FileCompleter(Completer):
366
366
  def user_confirm(tip: str, default: bool = True) -> bool:
367
367
  """提示用户确认是/否问题"""
368
368
  try:
369
+ from jarvis.jarvis_utils.config import is_non_interactive
370
+ if is_non_interactive():
371
+ return default
369
372
  suffix = "[Y/n]" if default else "[y/N]"
370
373
  ret = get_single_line_input(f"{tip} {suffix}: ")
371
374
  return default if ret == "" else ret.lower() == "y"
@@ -663,6 +666,9 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
663
666
  preset: Optional[str] = None
664
667
  preset_cursor: Optional[int] = None
665
668
  while True:
669
+ from jarvis.jarvis_utils.config import is_non_interactive
670
+ if is_non_interactive():
671
+ return "我无法与你交互,所有的事情你都自我决策,如果无法决策,就完成任务"
666
672
  user_input = _get_multiline_input_internal(
667
673
  tip, preset=preset, preset_cursor=preset_cursor
668
674
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.3.32
3
+ Version: 0.3.34
4
4
  Summary: Jarvis: An AI assistant that uses tools to interact with the system
5
5
  Home-page: https://github.com/skyfireitdiy/Jarvis
6
6
  Author: skyfire
@@ -1,15 +1,16 @@
1
- jarvis/__init__.py,sha256=FrY3n45NnZ384YSR1UaQF1-ryuCK5R3PbKYXg7dMa7I,74
2
- jarvis/jarvis_agent/__init__.py,sha256=Mp0lcivL99cL2eIjHz-D1C86XMOhJkFYtnQcJoflfH4,49033
3
- jarvis/jarvis_agent/agent_manager.py,sha256=qNcMy5Xc5ZT26JfczBg4b4D5udKVHSFsCFjlpbIdmPo,3076
1
+ jarvis/__init__.py,sha256=ox9PkCGjGlQ9QXXXe5Ew6Wz9Ko3PNyfVq7XzjTFuafU,74
2
+ jarvis/jarvis_agent/__init__.py,sha256=KNSsotISHDThdLIX9VNAHtm_0fxyf9ZrjlKVxP0ZFCE,49176
3
+ jarvis/jarvis_agent/agent_manager.py,sha256=ZjaSEqn7otkQ9Y7Yz8jPqUdDoKqmZ4zpSnYDl5fb8I0,3352
4
4
  jarvis/jarvis_agent/builtin_input_handler.py,sha256=wS-FqpT3pIXwHn1dfL3SpXonUKWgVThbQueUIeyRc2U,2917
5
- jarvis/jarvis_agent/config.py,sha256=Ni1aTVzmdERJ89A1jsC21Tsys_9MM-TTx1w5XwxyEwA,3130
5
+ jarvis/jarvis_agent/config.py,sha256=7rSYmgx9hI-PnWA2PLjubOxAbH7_NEDmnDvy6iAnPbQ,3362
6
6
  jarvis/jarvis_agent/config_editor.py,sha256=hlb9EYxKWcR_qdW2O89CgNDdciR9Isi743JU_1gD8j4,1927
7
7
  jarvis/jarvis_agent/edit_file_handler.py,sha256=7xkEvlER6pNHtxyGad_ol23NeDGsYMunq4XmTAx86kw,24722
8
8
  jarvis/jarvis_agent/event_bus.py,sha256=pRdfk7d0OG18K6yNfWlCvAh_dW5p9sBtT2Yc3jGmzgo,1519
9
9
  jarvis/jarvis_agent/events.py,sha256=rmFQ37PasImCh7OCdCzNBvubk-kHwcUiYLgzmL0t0_4,3689
10
+ jarvis/jarvis_agent/file_context_handler.py,sha256=2MPn_O_2llX39meFg272Cjk3wMPn5nmgbGMUyX06YQo,2113
10
11
  jarvis/jarvis_agent/file_methodology_manager.py,sha256=LnhgTx5xQXCBK8esjCkFbgFm9iEyFX7TryUlC40Kzpw,4428
11
- jarvis/jarvis_agent/jarvis.py,sha256=20xdLdAaiOo5nriIt3ZkRzOBW_UTrFrPvwjfDp62tKU,27083
12
- jarvis/jarvis_agent/main.py,sha256=bFcwXWC6O05jQiXy6ED_bHjdjDo5VwV_i1BoBEAzgP0,3336
12
+ jarvis/jarvis_agent/jarvis.py,sha256=oONAMya0MeFWC7vGQ4NvC09JoAMwgIkHsMXBKiczSiY,32640
13
+ jarvis/jarvis_agent/main.py,sha256=IgS7d3rng2vFlu983OUeCkOAosKjFAn1sFCk3gT9J9Q,4563
13
14
  jarvis/jarvis_agent/memory_manager.py,sha256=WSyUffx9xTmkcj4QrSLEfsjI3sTMUwZmkkC9_N_gTjo,8042
14
15
  jarvis/jarvis_agent/methodology_share_manager.py,sha256=AB_J9BwRgaeENQfL6bH83FOLeLrgHhppMb7psJNevKs,6874
15
16
  jarvis/jarvis_agent/output_handler.py,sha256=P7oWpXBGFfOsWq7cIhS_z9crkQ19ES7qU5pM92KKjAs,1172
@@ -17,7 +18,7 @@ jarvis/jarvis_agent/prompt_builder.py,sha256=PH1fPDVa8z_RXkoXHJFNDf8PQjUoLNLYwkh
17
18
  jarvis/jarvis_agent/prompt_manager.py,sha256=_1qLBSA3yn4nT_N3X2npTpW40Cp-pMeyvnzu-pnG0iU,2720
18
19
  jarvis/jarvis_agent/prompts.py,sha256=CvbPYx_klEz6OQrxVReZAnC2uQNo53rWkkucmh30uKg,9531
19
20
  jarvis/jarvis_agent/protocols.py,sha256=YFJaC9MHi7JfLzmvlyotJDjiCO4Z07XJXy1gKhVdUy4,956
20
- jarvis/jarvis_agent/run_loop.py,sha256=GdOERKfQUTx5EtHMA-4ilmA__SJzXksheP44Oo6HF9c,4300
21
+ jarvis/jarvis_agent/run_loop.py,sha256=OWdJSq1dLC6xPx4EQBfSnD_rb3IwszwZp4KbXYiJtcg,4747
21
22
  jarvis/jarvis_agent/session_manager.py,sha256=5wVcaZGwJ9cEKTQglSbqyxUDJ2fI5KxYN8C8L16UWLw,3024
22
23
  jarvis/jarvis_agent/share_manager.py,sha256=MF2RlomcgPxF8nVUk28DP6IRddZ_tot5l_YRvy0qXSQ,8726
23
24
  jarvis/jarvis_agent/shell_input_handler.py,sha256=wiAPjB-9uTkcLszbO5dlOUwIfaeR39RgRcZhahIGqoA,2018
@@ -28,7 +29,7 @@ jarvis/jarvis_agent/tool_share_manager.py,sha256=Do08FRxis0ynwR2a6iRoa6Yq0qCP8Nk
28
29
  jarvis/jarvis_agent/user_interaction.py,sha256=tifFN49GkO_Q80sqOTVmhxwbNWTazF3K0cr8AnnvzdU,1453
29
30
  jarvis/jarvis_agent/utils.py,sha256=ldgfuNTNu4JU7Y1LtystBl85OC6H3A4OMycg0XBt_Cs,1615
30
31
  jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
- jarvis/jarvis_code_agent/code_agent.py,sha256=nCe0GP6mIzAjJBn2aFqVrDRSjMHnenkDrSoaM0VY87U,36576
32
+ jarvis/jarvis_code_agent/code_agent.py,sha256=G5owx0sm9ge8rWpiiTw9vPRVmZ2fAV9chKoyVmvFpQ8,38101
32
33
  jarvis/jarvis_code_agent/lint.py,sha256=_qLJB_bC3PuoHG-j4EGOnYzNGO26jHlKLbkysfyQW1c,3954
33
34
  jarvis/jarvis_code_analysis/code_review.py,sha256=Z0JsvyVPPHPm6rfo4fqaQr7CdZKIllo9jqStzV0i_-o,34470
34
35
  jarvis/jarvis_code_analysis/checklists/__init__.py,sha256=LIXAYa1sW3l7foP6kohLWnE98I_EQ0T7z5bYKHq6rJA,78
@@ -51,7 +52,7 @@ jarvis/jarvis_code_analysis/checklists/shell.py,sha256=aRFYhQQvTgbYd-uY5pc8UHIUA
51
52
  jarvis/jarvis_code_analysis/checklists/sql.py,sha256=vR0T6qC7b4dURjJVAd7kSVxyvZEQXPG1Jqc2sNTGp5c,2355
52
53
  jarvis/jarvis_code_analysis/checklists/swift.py,sha256=TPx4I6Gupvs6tSerRKmTSKEPQpOLEbH2Y7LXg1uBgxc,2566
53
54
  jarvis/jarvis_code_analysis/checklists/web.py,sha256=25gGD7pDadZQybNFvALYxWvK0VRjGQb1NVJQElwjyk0,3943
54
- jarvis/jarvis_data/config_schema.json,sha256=q5kXr067yPYcebEWyhqFBmfX1KgyjTAr_hCku__zSZ4,14166
55
+ jarvis/jarvis_data/config_schema.json,sha256=IlQ2u6lNvn1y31NNr544cUkH8GS9wQSbWJCiOlGjZMo,14497
55
56
  jarvis/jarvis_data/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4,sha256=Ijkht27pm96ZW3_3OFE-7xAPtR0YyTWXoRO8_-hlsqc,1681126
56
57
  jarvis/jarvis_git_squash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
58
  jarvis/jarvis_git_squash/main.py,sha256=BRbsEQVXwseVFKliVqV8_JPh1om6QT6dLTHw0jQ7OE0,2474
@@ -63,11 +64,11 @@ jarvis/jarvis_mcp/streamable_mcp_client.py,sha256=BenOeZGNHdUOJT5Z3cc5MhS6aOeKQg
63
64
  jarvis/jarvis_memory_organizer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
65
  jarvis/jarvis_memory_organizer/memory_organizer.py,sha256=CMFL46vvtpcTI6oS3CAlYteR6xAlwCkvVJmMT22uDRw,26295
65
66
  jarvis/jarvis_methodology/main.py,sha256=uiNzk5b5O6xdvRhsOuD7ubxdd2tPcDsFFnvmes8uH8I,11370
66
- jarvis/jarvis_multi_agent/__init__.py,sha256=OD3ZyuxPNPHaqjQqiKiW0HuB0DI_sdv41wFlCISHWIQ,6084
67
- jarvis/jarvis_multi_agent/main.py,sha256=b9IThFMeUZCYSlgT-VT8r7xeBdrEE_zNT11awEc8IdY,1853
67
+ jarvis/jarvis_multi_agent/__init__.py,sha256=fBWmW5S9gpEEYzCBJizyE2q0Jj2LUzj4yh7sfoe3Qrc,7170
68
+ jarvis/jarvis_multi_agent/main.py,sha256=XXdZ9Gz2QrVaN5Rg45mUMI5K9dEJWBwr-wp4rSRQCIc,3002
68
69
  jarvis/jarvis_platform/__init__.py,sha256=WLQHSiE87PPket2M50_hHzjdMIgPIBx2VF8JfB_NNRk,105
69
70
  jarvis/jarvis_platform/ai8.py,sha256=g8JkqPGs9SEbqstNMCc5rCHO0QcPHX9LNvb7HMWwB-Q,11471
70
- jarvis/jarvis_platform/base.py,sha256=u1XvfE83-S-3W_euMrMaaa8NdXeIHlo7VSxLBbN3K-Y,13504
71
+ jarvis/jarvis_platform/base.py,sha256=NhhiAiACNsL462zljtGsG61SD8X-RRJyOAz1n1ocAPw,15947
71
72
  jarvis/jarvis_platform/human.py,sha256=jWjW8prEag79e6ddqTPV4nz_Gz6zFBfO4a1EbvP8QWA,4908
72
73
  jarvis/jarvis_platform/kimi.py,sha256=KLsf9udAsPRMbQ2JkBeiAlXkupCBwdtMaJ-hpH4Jdkc,15711
73
74
  jarvis/jarvis_platform/openai.py,sha256=4YapmkmJmPGfrjktORcIejlB98b83Wsi_48zjBymHAc,9500
@@ -98,17 +99,17 @@ jarvis/jarvis_tools/ask_user.py,sha256=M6DdLNryCE8y1JcdZHEifUgZkPUEPNKc-zDW5p0Mb
98
99
  jarvis/jarvis_tools/base.py,sha256=tFZkRlbV_a-pbjM-ci9AYmXVJm__FXuzVWKbQEyz4Ao,1639
99
100
  jarvis/jarvis_tools/clear_memory.py,sha256=8DOq6dHLemfKTJqu227PWBIp8Iu5K7EXwINzL8DYk8M,8205
100
101
  jarvis/jarvis_tools/edit_file.py,sha256=UcJNTVCDEmRaQsN_7_Ip2LjrTDm4wWzj2deuZHiBvLI,9026
101
- jarvis/jarvis_tools/execute_script.py,sha256=oDOMn8GcV6qKP4d0RFT6xbHGTazRmaOlp-h_e_Wj80c,6227
102
+ jarvis/jarvis_tools/execute_script.py,sha256=kjl-c6OmQPEeGqEjbuEGoGhb2nAiQoYzz2_2_Y3tIlY,8277
102
103
  jarvis/jarvis_tools/file_analyzer.py,sha256=jzVb8fAJn3dWwpCiYH-Wuxva4kpHqBB2_V3x3mzY0Gs,4158
103
104
  jarvis/jarvis_tools/generate_new_tool.py,sha256=tJz0YtfDwyH9y00VEWw3Btqr9JCNhvtI8BN9i5hYk_M,8560
104
105
  jarvis/jarvis_tools/methodology.py,sha256=_K4GIDUodGEma3SvNRo7Qs5rliijgNespVLyAPN35JU,5233
105
106
  jarvis/jarvis_tools/read_code.py,sha256=F1RuO0c69t0h7CvrUGqrTyNcOCcUrFQPACc61O_YSso,6382
106
- jarvis/jarvis_tools/read_webpage.py,sha256=YTmoalY8y-jdQuoj9IL6ZjXPOevUj2P_9arJngPhbUY,5317
107
+ jarvis/jarvis_tools/read_webpage.py,sha256=dfyXJ9vaX-ZRbua1P5ZlaU_SlSzKkeNw-1kI_3-gxFE,5433
107
108
  jarvis/jarvis_tools/registry.py,sha256=yVXBrJ7plyn7Dr3dD6mPmgd6eiBftmd19Cc84-PwVN8,33312
108
109
  jarvis/jarvis_tools/retrieve_memory.py,sha256=hhhGSr7jebPHICY9oEKICyI8mfqsRtKjh58qZNZApKc,8624
109
110
  jarvis/jarvis_tools/rewrite_file.py,sha256=CuvjWPTbUaPbex9FKSmw_Ru4r6R-CX_3vqTqCTp8nHA,6959
110
111
  jarvis/jarvis_tools/save_memory.py,sha256=RQtNxcpU53FFv_EBjH0i0oyQ7jWubm-trD1BHuqaGjI,6985
111
- jarvis/jarvis_tools/search_web.py,sha256=nkbmyIquGLl2JkgWP6pQ9dPcLlfQCuegwt_RKE0YWU0,6158
112
+ jarvis/jarvis_tools/search_web.py,sha256=Hi8WBxcRH02qjOF1qcJP2qSqs3kVOKGFAARfh548Ii4,6370
112
113
  jarvis/jarvis_tools/sub_agent.py,sha256=kjMZBXQE3OUgm5eO9lNkOuBnugWQGZbCpVP0HNW5W2s,8905
113
114
  jarvis/jarvis_tools/sub_code_agent.py,sha256=vVPcGKfgyhbZzl8vp2HHbgR1oQzC0TlS0G3THoZgU5Q,9453
114
115
  jarvis/jarvis_tools/virtual_tty.py,sha256=L7-J00ARQvIa25T45Hhqg2eCBl6W2LFgqDlWMWf-7dk,25275
@@ -117,21 +118,21 @@ jarvis/jarvis_tools/cli/main.py,sha256=WL2GNV7WqYl7G1-btRGvCkzDCMk4fPfNvzCrnUFVP
117
118
  jarvis/jarvis_utils/__init__.py,sha256=67h0ldisGlh3oK4DAeNEL2Bl_VsI3tSmfclasyVlueM,850
118
119
  jarvis/jarvis_utils/builtin_replace_map.py,sha256=z8iAqsbZUiGFaozxG1xSu128op8udqHOeEw-GxNt4bU,1708
119
120
  jarvis/jarvis_utils/clipboard.py,sha256=D3wzQeqg_yiH7Axs4d6MRxyNa9XxdnenH-ND2uj2WVQ,2967
120
- jarvis/jarvis_utils/config.py,sha256=AbDfL6hBpD6G_cRlr_bOAXECsj_vIq9tHXgkbsBIv5E,21119
121
+ jarvis/jarvis_utils/config.py,sha256=w_TWfEBabnTgQxJ2CWuP6V36Q1inOwMZLcJRziqV2t4,22363
121
122
  jarvis/jarvis_utils/embedding.py,sha256=x6mrkL7Bc3qgfuBDsjc4fg4nKG8ofGxVLVVydbsb8PY,2838
122
123
  jarvis/jarvis_utils/file_processors.py,sha256=XiM248SHS7lLgQDCbORVFWqinbVDUawYxWDOsLXDxP8,3043
123
124
  jarvis/jarvis_utils/fzf.py,sha256=vCs0Uh5dUqGbWzXn2JCtLLCOYE2B39ZNdNveR9PK4DA,1681
124
125
  jarvis/jarvis_utils/git_utils.py,sha256=zxjdxbFb_X6aYo-w1fbMx3d2n1ScbmmaAYlE3wGaaSg,24071
125
126
  jarvis/jarvis_utils/globals.py,sha256=7Xvf9HY6jYJL4vSD1F1WCoxHkHCAyltJUYt4V9gGVU4,8865
126
127
  jarvis/jarvis_utils/http.py,sha256=eRhV3-GYuWmQ0ogq9di9WMlQkFcVb1zGCrySnOgT1x0,4392
127
- jarvis/jarvis_utils/input.py,sha256=BT-aAaOBFsb4YeqR5ceIsa-j_MYEmsAvQqrXQSknA7c,36536
128
+ jarvis/jarvis_utils/input.py,sha256=muopeZc68N-_tM7ERI2aazqernLumF-sQqS_JfWI0jI,36879
128
129
  jarvis/jarvis_utils/methodology.py,sha256=z_renvRGgHiC-XTQPuN6rvrJ_ffHlwxK_b1BU_jmNAQ,12800
129
130
  jarvis/jarvis_utils/output.py,sha256=y2fVcao_2ZowFl0IxUrJZCi8T6ZM0z-iPzpk8T8eLxc,13623
130
131
  jarvis/jarvis_utils/tag.py,sha256=f211opbbbTcSyzCDwuIK_oCnKhXPNK-RknYyGzY1yD0,431
131
132
  jarvis/jarvis_utils/utils.py,sha256=uMtfaStxDtp2i9AFIxwtPKgSxLwQxw8Z2rXsX-ZGlis,72728
132
- jarvis_ai_assistant-0.3.32.dist-info/licenses/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
133
- jarvis_ai_assistant-0.3.32.dist-info/METADATA,sha256=LOLHRMK96T6elM3uhhd7Isu3xNPlhJkYYtt3Ok3lGts,18752
134
- jarvis_ai_assistant-0.3.32.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
135
- jarvis_ai_assistant-0.3.32.dist-info/entry_points.txt,sha256=4GcWKFxRJD-QU14gw_3ZaW4KuEVxOcZK9i270rwPdjA,1395
136
- jarvis_ai_assistant-0.3.32.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
137
- jarvis_ai_assistant-0.3.32.dist-info/RECORD,,
133
+ jarvis_ai_assistant-0.3.34.dist-info/licenses/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
134
+ jarvis_ai_assistant-0.3.34.dist-info/METADATA,sha256=fmIYdg00CuxGJa4bjpaRU28NaMonvmku6NTcAQAFymI,18752
135
+ jarvis_ai_assistant-0.3.34.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
136
+ jarvis_ai_assistant-0.3.34.dist-info/entry_points.txt,sha256=4GcWKFxRJD-QU14gw_3ZaW4KuEVxOcZK9i270rwPdjA,1395
137
+ jarvis_ai_assistant-0.3.34.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
138
+ jarvis_ai_assistant-0.3.34.dist-info/RECORD,,