jarvis-ai-assistant 0.2.6__tar.gz → 0.2.7__tar.gz

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 (124) hide show
  1. {jarvis_ai_assistant-0.2.6/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.2.7}/PKG-INFO +1 -1
  2. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/pyproject.toml +1 -1
  3. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/setup.py +1 -1
  4. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/__init__.py +1 -1
  5. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_agent/__init__.py +12 -1
  6. jarvis_ai_assistant-0.2.7/src/jarvis/jarvis_agent/jarvis.py +462 -0
  7. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_agent/code_agent.py +1 -0
  8. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_data/config_schema.json +5 -0
  9. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_stats/storage.py +2 -2
  10. jarvis_ai_assistant-0.2.7/src/jarvis/jarvis_tools/clear_memory.py +252 -0
  11. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/retrieve_memory.py +17 -11
  12. jarvis_ai_assistant-0.2.7/src/jarvis/jarvis_tools/save_memory.py +203 -0
  13. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/config.py +10 -0
  14. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/input.py +5 -3
  15. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/methodology.py +41 -6
  16. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/output.py +1 -1
  17. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7/src/jarvis_ai_assistant.egg-info}/PKG-INFO +1 -1
  18. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis_ai_assistant.egg-info/SOURCES.txt +1 -0
  19. jarvis_ai_assistant-0.2.6/src/jarvis/jarvis_agent/jarvis.py +0 -230
  20. jarvis_ai_assistant-0.2.6/src/jarvis/jarvis_tools/save_memory.py +0 -142
  21. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/LICENSE +0 -0
  22. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/MANIFEST.in +0 -0
  23. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/README.md +0 -0
  24. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/setup.cfg +0 -0
  25. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_agent/builtin_input_handler.py +0 -0
  26. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_agent/edit_file_handler.py +0 -0
  27. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_agent/main.py +0 -0
  28. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_agent/output_handler.py +0 -0
  29. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_agent/prompt_builder.py +0 -0
  30. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_agent/prompts.py +0 -0
  31. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_agent/protocols.py +0 -0
  32. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_agent/session_manager.py +0 -0
  33. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_agent/shell_input_handler.py +0 -0
  34. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_agent/tool_executor.py +0 -0
  35. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_agent/__init__.py +0 -0
  36. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_agent/lint.py +0 -0
  37. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/__init__.py +0 -0
  38. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/c_cpp.py +0 -0
  39. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/csharp.py +0 -0
  40. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/data_format.py +0 -0
  41. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/devops.py +0 -0
  42. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/docs.py +0 -0
  43. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/go.py +0 -0
  44. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/infrastructure.py +0 -0
  45. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/java.py +0 -0
  46. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/javascript.py +0 -0
  47. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/kotlin.py +0 -0
  48. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/loader.py +0 -0
  49. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/php.py +0 -0
  50. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/python.py +0 -0
  51. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/ruby.py +0 -0
  52. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/rust.py +0 -0
  53. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/shell.py +0 -0
  54. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/sql.py +0 -0
  55. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/swift.py +0 -0
  56. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/checklists/web.py +0 -0
  57. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_code_analysis/code_review.py +0 -0
  58. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_data/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +0 -0
  59. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_git_squash/__init__.py +0 -0
  60. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_git_squash/main.py +0 -0
  61. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_git_utils/git_commiter.py +0 -0
  62. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_mcp/__init__.py +0 -0
  63. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_mcp/sse_mcp_client.py +0 -0
  64. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_mcp/stdio_mcp_client.py +0 -0
  65. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_mcp/streamable_mcp_client.py +0 -0
  66. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_methodology/main.py +0 -0
  67. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_multi_agent/__init__.py +0 -0
  68. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_multi_agent/main.py +0 -0
  69. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_platform/__init__.py +0 -0
  70. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_platform/ai8.py +0 -0
  71. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_platform/base.py +0 -0
  72. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_platform/human.py +0 -0
  73. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_platform/kimi.py +0 -0
  74. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_platform/openai.py +0 -0
  75. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_platform/registry.py +0 -0
  76. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_platform/tongyi.py +0 -0
  77. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_platform/yuanbao.py +0 -0
  78. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_platform_manager/__init__.py +0 -0
  79. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_platform_manager/main.py +0 -0
  80. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_platform_manager/service.py +0 -0
  81. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_rag/__init__.py +0 -0
  82. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_rag/cache.py +0 -0
  83. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_rag/cli.py +0 -0
  84. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_rag/embedding_manager.py +0 -0
  85. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_rag/llm_interface.py +0 -0
  86. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_rag/query_rewriter.py +0 -0
  87. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_rag/rag_pipeline.py +0 -0
  88. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_rag/reranker.py +0 -0
  89. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_rag/retriever.py +0 -0
  90. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_smart_shell/__init__.py +0 -0
  91. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_smart_shell/main.py +0 -0
  92. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_stats/__init__.py +0 -0
  93. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_stats/cli.py +0 -0
  94. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_stats/stats.py +0 -0
  95. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_stats/visualizer.py +0 -0
  96. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/__init__.py +0 -0
  97. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/ask_user.py +0 -0
  98. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/base.py +0 -0
  99. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/cli/__init__.py +0 -0
  100. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/cli/main.py +0 -0
  101. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/edit_file.py +0 -0
  102. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/execute_script.py +0 -0
  103. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/file_analyzer.py +0 -0
  104. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/generate_new_tool.py +0 -0
  105. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/methodology.py +0 -0
  106. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/read_code.py +0 -0
  107. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/read_webpage.py +0 -0
  108. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/registry.py +0 -0
  109. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/rewrite_file.py +0 -0
  110. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/search_web.py +0 -0
  111. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_tools/virtual_tty.py +0 -0
  112. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/__init__.py +0 -0
  113. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/builtin_replace_map.py +0 -0
  114. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/embedding.py +0 -0
  115. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/file_processors.py +0 -0
  116. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/git_utils.py +0 -0
  117. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/globals.py +0 -0
  118. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/http.py +0 -0
  119. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/tag.py +0 -0
  120. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis/jarvis_utils/utils.py +0 -0
  121. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis_ai_assistant.egg-info/dependency_links.txt +0 -0
  122. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis_ai_assistant.egg-info/entry_points.txt +0 -0
  123. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis_ai_assistant.egg-info/requires.txt +0 -0
  124. {jarvis_ai_assistant-0.2.6 → jarvis_ai_assistant-0.2.7}/src/jarvis_ai_assistant.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.2.6
3
+ Version: 0.2.7
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "jarvis-ai-assistant"
7
- version = "0.2.6"
7
+ version = "0.2.7"
8
8
  description = "Jarvis: An AI assistant that uses tools to interact with the system"
9
9
  readme = "README.md"
10
10
  authors = [{ name = "skyfire", email = "skyfireitdiy@hotmail.com" }]
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages # type: ignore
3
3
 
4
4
  setup(
5
5
  name="jarvis-ai-assistant",
6
- version="0.2.6",
6
+ version="0.2.7",
7
7
  author="skyfire",
8
8
  author_email="skyfireitdiy@hotmail.com",
9
9
  description="An AI assistant that uses various tools to interact with the system",
@@ -1,4 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Jarvis AI Assistant"""
3
3
 
4
- __version__ = "0.2.6"
4
+ __version__ = "0.2.7"
@@ -614,8 +614,19 @@ class Agent:
614
614
  memory_tags = get_all_memory_tags()
615
615
  memory_tags_prompt = ""
616
616
 
617
+ # 检查是否有save_memory工具
618
+ tool_registry = self.get_tool_registry()
619
+ has_save_memory = False
620
+ if tool_registry:
621
+ tool_names = [tool.name for tool in tool_registry.tools.values()]
622
+ has_save_memory = "save_memory" in tool_names
623
+
624
+ # 如果有save_memory工具,添加记录关键信息的提示
625
+ if has_save_memory:
626
+ memory_tags_prompt = "\n\n💡 提示:在分析任务之前,建议使用 save_memory 工具将关键信息记录下来,便于后续检索和复用。"
627
+
617
628
  if any(tags for tags in memory_tags.values()):
618
- memory_tags_prompt = "\n\n系统中存在以下记忆标签,你可以使用 retrieve_memory 工具检索相关记忆:"
629
+ memory_tags_prompt += "\n\n系统中存在以下记忆标签,你可以使用 retrieve_memory 工具检索相关记忆:"
619
630
  for memory_type, tags in memory_tags.items():
620
631
  if tags:
621
632
  type_name = {
@@ -0,0 +1,462 @@
1
+ # -*- coding: utf-8 -*-
2
+ import os
3
+ import shutil
4
+ import subprocess
5
+ import sys
6
+ from pathlib import Path
7
+ from typing import Dict, Optional, List
8
+
9
+ import typer
10
+ import yaml # type: ignore
11
+ from prompt_toolkit import prompt # type: ignore
12
+
13
+ from jarvis.jarvis_agent import (
14
+ Agent,
15
+ OutputType,
16
+ PrettyOutput,
17
+ get_multiline_input,
18
+ origin_agent_system_prompt,
19
+ user_confirm,
20
+ )
21
+ from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
22
+ from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
23
+ from jarvis.jarvis_tools.registry import ToolRegistry
24
+ from jarvis.jarvis_utils.config import get_data_dir
25
+ from jarvis.jarvis_utils.utils import init_env
26
+
27
+ app = typer.Typer(help="Jarvis AI 助手")
28
+
29
+
30
+ def _load_tasks() -> Dict[str, str]:
31
+ """Load tasks from .jarvis files in user home and current directory."""
32
+ tasks: Dict[str, str] = {}
33
+
34
+ # Check pre-command in data directory
35
+ data_dir = get_data_dir()
36
+ pre_command_path = os.path.join(data_dir, "pre-command")
37
+ if os.path.exists(pre_command_path):
38
+ print(f"🔍 从{pre_command_path}加载预定义任务...")
39
+ try:
40
+ with open(pre_command_path, "r", encoding="utf-8", errors="ignore") as f:
41
+ user_tasks = yaml.safe_load(f)
42
+ if isinstance(user_tasks, dict):
43
+ for name, desc in user_tasks.items():
44
+ if desc:
45
+ tasks[str(name)] = str(desc)
46
+ print(f"✅ 预定义任务加载完成 {pre_command_path}")
47
+ except (yaml.YAMLError, OSError):
48
+ print(f"❌ 预定义任务加载失败 {pre_command_path}")
49
+
50
+ # Check .jarvis/pre-command in current directory
51
+ pre_command_path = ".jarvis/pre-command"
52
+ if os.path.exists(pre_command_path):
53
+ abs_path = os.path.abspath(pre_command_path)
54
+ print(f"🔍 从{abs_path}加载预定义任务...")
55
+ try:
56
+ with open(pre_command_path, "r", encoding="utf-8", errors="ignore") as f:
57
+ local_tasks = yaml.safe_load(f)
58
+ if isinstance(local_tasks, dict):
59
+ for name, desc in local_tasks.items():
60
+ if desc:
61
+ tasks[str(name)] = str(desc)
62
+ print(f"✅ 预定义任务加载完成 {pre_command_path}")
63
+ except (yaml.YAMLError, OSError):
64
+ print(f"❌ 预定义任务加载失败 {pre_command_path}")
65
+
66
+ return tasks
67
+
68
+
69
+ def _select_task(tasks: Dict[str, str]) -> str:
70
+ """Let user select a task from the list or skip. Returns task description if selected."""
71
+ if not tasks:
72
+ return ""
73
+
74
+ task_names = list(tasks.keys())
75
+ task_list = ["可用任务:"]
76
+ for i, name in enumerate(task_names, 1):
77
+ task_list.append(f"[{i}] {name}")
78
+ task_list.append("[0] 跳过预定义任务")
79
+ PrettyOutput.print("\n".join(task_list), OutputType.INFO)
80
+
81
+ while True:
82
+ try:
83
+ choice_str = prompt("\n请选择一个任务编号(0 跳过预定义任务):").strip()
84
+ if not choice_str:
85
+ return ""
86
+
87
+ choice = int(choice_str)
88
+ if choice == 0:
89
+ return ""
90
+ if 1 <= choice <= len(task_names):
91
+ selected_task = tasks[task_names[choice - 1]]
92
+ PrettyOutput.print(f"将要执行任务:\n {selected_task}", OutputType.INFO)
93
+ # 询问是否需要补充信息
94
+ need_additional = user_confirm(
95
+ "需要为此任务添加补充信息吗?", default=False
96
+ )
97
+ if need_additional:
98
+ additional_input = get_multiline_input("请输入补充信息:")
99
+ if additional_input:
100
+ selected_task = (
101
+ f"{selected_task}\n\n补充信息:\n{additional_input}"
102
+ )
103
+ return selected_task
104
+ PrettyOutput.print(
105
+ "无效的选择。请选择列表中的一个号码。", OutputType.WARNING
106
+ )
107
+
108
+ except (KeyboardInterrupt, EOFError):
109
+ return ""
110
+ except ValueError as val_err:
111
+ PrettyOutput.print(f"选择任务失败: {str(val_err)}", OutputType.ERROR)
112
+
113
+
114
+ def _handle_edit_mode(edit: bool, config_file: Optional[str]) -> None:
115
+ """If edit flag is set, open config file in editor and exit."""
116
+ if not edit:
117
+ return
118
+
119
+ config_file_path = (
120
+ Path(config_file)
121
+ if config_file
122
+ else Path(os.path.expanduser("~/.jarvis/config.yaml"))
123
+ )
124
+ # 根据操作系统选择合适的编辑器
125
+ import platform
126
+
127
+ if platform.system() == "Windows":
128
+ # 优先级:终端工具 -> 代码编辑器 -> 通用文本编辑器
129
+ editors = ["nvim", "vim", "nano", "code", "notepad++", "notepad"]
130
+ else:
131
+ # 优先级:终端工具 -> 代码编辑器 -> 通用文本编辑器
132
+ editors = ["nvim", "vim", "vi", "nano", "emacs", "code", "gedit", "kate"]
133
+
134
+ editor = next((e for e in editors if shutil.which(e)), None)
135
+
136
+ if editor:
137
+ try:
138
+ subprocess.run([editor, str(config_file_path)], check=True)
139
+ raise typer.Exit(code=0)
140
+ except (subprocess.CalledProcessError, FileNotFoundError) as e:
141
+ PrettyOutput.print(f"Failed to open editor: {e}", OutputType.ERROR)
142
+ raise typer.Exit(code=1)
143
+ else:
144
+ PrettyOutput.print(
145
+ f"No suitable editor found. Tried: {', '.join(editors)}", OutputType.ERROR
146
+ )
147
+ raise typer.Exit(code=1)
148
+
149
+
150
+ def _initialize_agent(
151
+ llm_type: str, model_group: Optional[str], restore_session: bool
152
+ ) -> Agent:
153
+ """Initialize the agent and restore session if requested."""
154
+ agent = Agent(
155
+ system_prompt=origin_agent_system_prompt,
156
+ llm_type=llm_type,
157
+ model_group=model_group,
158
+ input_handler=[shell_input_handler, builtin_input_handler],
159
+ output_handler=[ToolRegistry()], # type: ignore
160
+ need_summary=False,
161
+ )
162
+
163
+ # 尝试恢复会话
164
+ if restore_session:
165
+ if agent.restore_session():
166
+ PrettyOutput.print("会话已成功恢复。", OutputType.SUCCESS)
167
+ else:
168
+ PrettyOutput.print("无法恢复会话。", OutputType.WARNING)
169
+ return agent
170
+
171
+
172
+ def _get_and_run_task(agent: Agent, task_content: Optional[str] = None) -> None:
173
+ """Get task from various sources and run it."""
174
+ # 优先处理命令行直接传入的任务
175
+ if task_content:
176
+ agent.run(task_content)
177
+ raise typer.Exit(code=0)
178
+
179
+ if agent.first:
180
+ tasks = _load_tasks()
181
+ if tasks and (selected_task := _select_task(tasks)):
182
+ PrettyOutput.print(f"开始执行任务: \n{selected_task}", OutputType.INFO)
183
+ agent.run(selected_task)
184
+ raise typer.Exit(code=0)
185
+
186
+ user_input = get_multiline_input("请输入你的任务(输入空行退出):")
187
+ if user_input:
188
+ agent.run(user_input)
189
+ raise typer.Exit(code=0)
190
+
191
+
192
+ def _parse_selection(selection_str: str, max_value: int) -> List[int]:
193
+ """解析用户输入的选择字符串,支持逗号分隔和范围选择
194
+
195
+ 例如: "1,2,3,4-9,20" -> [1, 2, 3, 4, 5, 6, 7, 8, 9, 20]
196
+ """
197
+ selected: set[int] = set()
198
+ parts = selection_str.split(",")
199
+
200
+ for part in parts:
201
+ part = part.strip()
202
+ if "-" in part:
203
+ # 处理范围选择
204
+ try:
205
+ start_str, end_str = part.split("-")
206
+ start_num = int(start_str.strip())
207
+ end_num = int(end_str.strip())
208
+ if 1 <= start_num <= max_value and 1 <= end_num <= max_value:
209
+ selected.update(range(start_num, end_num + 1))
210
+ except ValueError:
211
+ continue
212
+ else:
213
+ # 处理单个数字
214
+ try:
215
+ num = int(part)
216
+ if 1 <= num <= max_value:
217
+ selected.add(num)
218
+ except ValueError:
219
+ continue
220
+
221
+ return sorted(list(selected))
222
+
223
+
224
+ def _handle_share_methodology(config_file: Optional[str] = None) -> None:
225
+ """处理方法论分享功能"""
226
+ from jarvis.jarvis_utils.config import (
227
+ get_central_methodology_repo,
228
+ get_methodology_dirs,
229
+ get_data_dir,
230
+ )
231
+ import glob
232
+ import json
233
+ import shutil
234
+
235
+ # 获取中心方法论仓库配置
236
+ central_repo = get_central_methodology_repo()
237
+ if not central_repo:
238
+ PrettyOutput.print(
239
+ "错误:未配置中心方法论仓库(JARVIS_CENTRAL_METHODOLOGY_REPO)",
240
+ OutputType.ERROR,
241
+ )
242
+ PrettyOutput.print("请在配置文件中设置中心方法论仓库的Git地址", OutputType.INFO)
243
+ raise typer.Exit(code=1)
244
+
245
+ # 克隆或更新中心方法论仓库
246
+ central_repo_path = os.path.join(get_data_dir(), "central_methodology_repo")
247
+ if not os.path.exists(central_repo_path):
248
+ PrettyOutput.print(f"正在克隆中心方法论仓库...", OutputType.INFO)
249
+ subprocess.run(["git", "clone", central_repo, central_repo_path], check=True)
250
+ else:
251
+ PrettyOutput.print(f"正在更新中心方法论仓库...", OutputType.INFO)
252
+ subprocess.run(["git", "pull"], cwd=central_repo_path, check=True)
253
+
254
+ # 获取中心仓库中已有的方法论
255
+ existing_methodologies = {} # 改为字典,存储 problem_type -> content 的映射
256
+ for filepath in glob.glob(os.path.join(central_repo_path, "*.json")):
257
+ try:
258
+ with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
259
+ methodology = json.load(f)
260
+ problem_type = methodology.get("problem_type", "")
261
+ content = methodology.get("content", "")
262
+ if problem_type and content:
263
+ existing_methodologies[problem_type] = content
264
+ except Exception:
265
+ pass
266
+
267
+ # 获取所有方法论目录
268
+ from jarvis.jarvis_utils.methodology import _get_methodology_directory
269
+
270
+ methodology_dirs = [_get_methodology_directory()] + get_methodology_dirs()
271
+
272
+ # 收集所有方法论文件(排除中心仓库目录和已存在的方法论)
273
+ all_methodologies = {}
274
+ methodology_files = []
275
+ seen_problem_types = set() # 用于去重
276
+
277
+ for directory in set(methodology_dirs):
278
+ # 跳过中心仓库目录
279
+ if os.path.abspath(directory) == os.path.abspath(central_repo_path):
280
+ continue
281
+
282
+ if not os.path.isdir(directory):
283
+ continue
284
+
285
+ for filepath in glob.glob(os.path.join(directory, "*.json")):
286
+ try:
287
+ with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
288
+ methodology = json.load(f)
289
+ problem_type = methodology.get("problem_type", "")
290
+ content = methodology.get("content", "")
291
+ # 基于内容判断是否已存在于中心仓库
292
+ is_duplicate = False
293
+ if problem_type in existing_methodologies:
294
+ # 如果problem_type相同,比较内容
295
+ if (
296
+ content.strip()
297
+ == existing_methodologies[problem_type].strip()
298
+ ):
299
+ is_duplicate = True
300
+
301
+ # 排除已存在于中心仓库的方法论(基于内容),以及本地重复的方法论
302
+ if (
303
+ problem_type
304
+ and content
305
+ and not is_duplicate
306
+ and problem_type not in seen_problem_types
307
+ ):
308
+ methodology_files.append(
309
+ {
310
+ "path": filepath,
311
+ "problem_type": problem_type,
312
+ "directory": directory,
313
+ }
314
+ )
315
+ all_methodologies[problem_type] = methodology
316
+ seen_problem_types.add(problem_type)
317
+ except Exception:
318
+ pass
319
+
320
+ if not methodology_files:
321
+ PrettyOutput.print(
322
+ "没有找到新的方法论文件(所有方法论可能已存在于中心仓库)",
323
+ OutputType.WARNING,
324
+ )
325
+ raise typer.Exit(code=0)
326
+
327
+ # 显示可选的方法论
328
+ methodology_list = ["\n可分享的方法论(已排除中心仓库中已有的):"]
329
+ for i, meth in enumerate(methodology_files, 1):
330
+ dir_name = os.path.basename(meth["directory"])
331
+ methodology_list.append(f"[{i}] {meth['problem_type']} (来自: {dir_name})")
332
+
333
+ # 一次性打印所有方法论
334
+ PrettyOutput.print("\n".join(methodology_list), OutputType.INFO)
335
+
336
+ # 让用户选择要分享的方法论
337
+ while True:
338
+ try:
339
+ choice_str = prompt(
340
+ "\n请选择要分享的方法论编号(支持格式: 1,2,3,4-9,20 或 all):"
341
+ ).strip()
342
+ if choice_str == "0":
343
+ raise typer.Exit(code=0)
344
+
345
+ selected_methodologies = []
346
+ if choice_str.lower() == "all":
347
+ selected_methodologies = methodology_files
348
+ else:
349
+ selected_indices = _parse_selection(choice_str, len(methodology_files))
350
+ if not selected_indices:
351
+ PrettyOutput.print("无效的选择", OutputType.WARNING)
352
+ continue
353
+ selected_methodologies = [
354
+ methodology_files[i - 1] for i in selected_indices
355
+ ]
356
+
357
+ # 确认操作
358
+ share_list = ["\n将要分享以下方法论到中心仓库:"]
359
+ for meth in selected_methodologies:
360
+ share_list.append(f"- {meth['problem_type']}")
361
+ PrettyOutput.print("\n".join(share_list), OutputType.INFO)
362
+
363
+ if not user_confirm("确认分享这些方法论吗?"):
364
+ continue
365
+
366
+ # 复制选中的方法论到中心仓库
367
+ copied_list = []
368
+ for meth in selected_methodologies:
369
+ src_file = meth["path"]
370
+ dst_file = os.path.join(central_repo_path, os.path.basename(src_file))
371
+ shutil.copy2(src_file, dst_file)
372
+ copied_list.append(f"已复制: {meth['problem_type']}")
373
+
374
+ # 一次性显示所有复制结果
375
+ if copied_list:
376
+ PrettyOutput.print("\n".join(copied_list), OutputType.SUCCESS)
377
+
378
+ # 提交并推送更改
379
+ PrettyOutput.print("\n正在提交更改...", OutputType.INFO)
380
+ subprocess.run(["git", "add", "."], cwd=central_repo_path, check=True)
381
+
382
+ commit_msg = f"Add {len(selected_methodologies)} methodology(ies) from local collection"
383
+ subprocess.run(
384
+ ["git", "commit", "-m", commit_msg], cwd=central_repo_path, check=True
385
+ )
386
+
387
+ PrettyOutput.print("正在推送到远程仓库...", OutputType.INFO)
388
+ subprocess.run(["git", "push"], cwd=central_repo_path, check=True)
389
+
390
+ PrettyOutput.print("\n方法论已成功分享到中心仓库!", OutputType.SUCCESS)
391
+ break
392
+
393
+ except ValueError:
394
+ PrettyOutput.print("请输入有效的数字", OutputType.WARNING)
395
+ except subprocess.CalledProcessError as e:
396
+ PrettyOutput.print(f"Git操作失败: {str(e)}", OutputType.ERROR)
397
+ raise typer.Exit(code=1)
398
+ except Exception as e:
399
+ PrettyOutput.print(f"分享方法论时出错: {str(e)}", OutputType.ERROR)
400
+ raise typer.Exit(code=1)
401
+
402
+
403
+ @app.callback(invoke_without_command=True)
404
+ def run_cli(
405
+ ctx: typer.Context,
406
+ llm_type: str = typer.Option(
407
+ "normal",
408
+ "--llm_type",
409
+ help="使用的LLM类型,可选值:'normal'(普通)或 'thinking'(思考模式)",
410
+ ),
411
+ task: Optional[str] = typer.Option(
412
+ None, "-t", "--task", help="从命令行直接输入任务内容"
413
+ ),
414
+ model_group: Optional[str] = typer.Option(
415
+ None, "--llm_group", help="使用的模型组,覆盖配置文件中的设置"
416
+ ),
417
+ config_file: Optional[str] = typer.Option(
418
+ None, "-f", "--config", help="自定义配置文件路径"
419
+ ),
420
+ restore_session: bool = typer.Option(
421
+ False,
422
+ "--restore-session",
423
+ help="从 .jarvis/saved_session.json 恢复会话",
424
+ ),
425
+ edit: bool = typer.Option(False, "-e", "--edit", help="编辑配置文件"),
426
+ share_methodology: bool = typer.Option(
427
+ False, "--share-methodology", help="分享本地方法论到中心方法论仓库"
428
+ ),
429
+ ) -> None:
430
+ """Jarvis AI assistant command-line interface."""
431
+ if ctx.invoked_subcommand is not None:
432
+ return
433
+
434
+ _handle_edit_mode(edit, config_file)
435
+
436
+ # 处理方法论分享
437
+ if share_methodology:
438
+ init_env("", config_file=config_file) # 初始化配置但不显示欢迎信息
439
+ _handle_share_methodology(config_file)
440
+ raise typer.Exit(code=0)
441
+
442
+ init_env(
443
+ "欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!", config_file=config_file
444
+ )
445
+
446
+ try:
447
+ agent = _initialize_agent(llm_type, model_group, restore_session)
448
+ _get_and_run_task(agent, task)
449
+ except typer.Exit:
450
+ raise
451
+ except Exception as err: # pylint: disable=broad-except
452
+ PrettyOutput.print(f"初始化错误: {str(err)}", OutputType.ERROR)
453
+ raise typer.Exit(code=1)
454
+
455
+
456
+ def main() -> None:
457
+ """Application entry point."""
458
+ app()
459
+
460
+
461
+ if __name__ == "__main__":
462
+ main()
@@ -67,6 +67,7 @@ class CodeAgent:
67
67
  "rewrite_file",
68
68
  "save_memory",
69
69
  "retrieve_memory",
70
+ "clear_memory",
70
71
  ]
71
72
  )
72
73
  code_system_prompt = """
@@ -225,6 +225,11 @@
225
225
  },
226
226
  "default": []
227
227
  },
228
+ "JARVIS_CENTRAL_METHODOLOGY_REPO": {
229
+ "type": "string",
230
+ "description": "中心方法论Git仓库地址,该仓库会自动添加到方法论加载路径中",
231
+ "default": ""
232
+ },
228
233
  "JARVIS_PRINT_PROMPT": {
229
234
  "type": "boolean",
230
235
  "description": "是否打印提示",
@@ -245,7 +245,7 @@ class StatsStorage:
245
245
  metrics_from_meta = set(meta.get("metrics", {}).keys())
246
246
 
247
247
  # 扫描所有数据文件获取实际存在的指标
248
- metrics_from_data = set()
248
+ metrics_from_data: set[str] = set()
249
249
  for data_file in self.data_dir.glob("stats_*.json"):
250
250
  try:
251
251
  data = self._load_json(data_file)
@@ -285,7 +285,7 @@ class StatsStorage:
285
285
  return {}
286
286
 
287
287
  # 聚合数据
288
- aggregated = defaultdict(
288
+ aggregated: Dict[str, Dict[str, Any]] = defaultdict(
289
289
  lambda: {
290
290
  "count": 0,
291
291
  "sum": 0,