jarvis-ai-assistant 0.1.225__py3-none-any.whl → 0.2.0__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.1.225"
4
+ __version__ = "0.2.0"
@@ -102,6 +102,7 @@ class Agent:
102
102
  name: str = "Jarvis",
103
103
  description: str = "",
104
104
  llm_type: str = "normal",
105
+ model_group: Optional[str] = None,
105
106
  summary_prompt: Optional[str] = None,
106
107
  auto_complete: bool = False,
107
108
  output_handler: List[OutputHandlerProtocol] = [],
@@ -137,11 +138,11 @@ class Agent:
137
138
  self.description = description
138
139
  # 初始化平台和模型
139
140
  if llm_type == "thinking":
140
- platform_name = get_thinking_platform_name()
141
- model_name = get_thinking_model_name()
141
+ platform_name = get_thinking_platform_name(model_group)
142
+ model_name = get_thinking_model_name(model_group)
142
143
  else: # 默认为 normal
143
- platform_name = get_normal_platform_name()
144
- model_name = get_normal_model_name()
144
+ platform_name = get_normal_platform_name(model_group)
145
+ model_name = get_normal_model_name(model_group)
145
146
 
146
147
  self.model = PlatformRegistry().create_platform(platform_name)
147
148
  if self.model is None:
@@ -153,6 +154,8 @@ class Agent:
153
154
  if model_name:
154
155
  self.model.set_model_name(model_name)
155
156
 
157
+ self.model.set_model_group(model_group)
158
+
156
159
  self.user_data: Dict[str, Any] = {}
157
160
 
158
161
  self.model.set_suppress_output(False)
@@ -197,7 +200,7 @@ class Agent:
197
200
  summary_prompt if summary_prompt else DEFAULT_SUMMARY_PROMPT
198
201
  )
199
202
 
200
- self.max_token_count = get_max_token_count()
203
+ self.max_token_count = get_max_token_count(model_group)
201
204
  self.auto_complete = auto_complete
202
205
  welcome_message = f"{name} 初始化完成 - 使用 {self.model.name()} 模型"
203
206
 
@@ -125,6 +125,11 @@ def _parse_args() -> argparse.Namespace:
125
125
  type=str,
126
126
  help="Directly input task content from command line",
127
127
  )
128
+ parser.add_argument(
129
+ "--model_group",
130
+ type=str,
131
+ help="Model group to use, overriding config",
132
+ )
128
133
  parser.add_argument("-f", "--config", type=str, help="Path to custom config file")
129
134
  parser.add_argument(
130
135
  "--restore-session",
@@ -170,6 +175,7 @@ def _initialize_agent(args: argparse.Namespace) -> Agent:
170
175
  agent = Agent(
171
176
  system_prompt=origin_agent_system_prompt,
172
177
  llm_type=args.llm_type,
178
+ model_group=args.model_group,
173
179
  input_handler=[shell_input_handler, builtin_input_handler],
174
180
  output_handler=[ToolRegistry()], # type: ignore
175
181
  need_summary=False,
@@ -52,6 +52,11 @@ def main():
52
52
  choices=["normal", "thinking"],
53
53
  help="LLM type to use, overriding config",
54
54
  )
55
+ parser.add_argument(
56
+ "--model_group",
57
+ type=str,
58
+ help="Model group to use, overriding config",
59
+ )
55
60
  args = parser.parse_args()
56
61
 
57
62
  # Initialize environment
@@ -65,6 +70,8 @@ def main():
65
70
  # Override config with command-line arguments if provided
66
71
  if args.llm_type:
67
72
  config["llm_type"] = args.llm_type
73
+ if args.model_group:
74
+ config["model_group"] = args.model_group
68
75
 
69
76
  # Create and run agent
70
77
  try:
@@ -47,6 +47,7 @@ class CodeAgent:
47
47
  def __init__(
48
48
  self,
49
49
  llm_type: str = "normal",
50
+ model_group: Optional[str] = None,
50
51
  need_summary: bool = True,
51
52
  ):
52
53
  self.root_dir = os.getcwd()
@@ -120,6 +121,7 @@ class CodeAgent:
120
121
  auto_complete=False,
121
122
  output_handler=[tool_registry, EditFileHandler()], # type: ignore
122
123
  llm_type=llm_type,
124
+ model_group=model_group,
123
125
  input_handler=[shell_input_handler, builtin_input_handler],
124
126
  need_summary=need_summary,
125
127
  use_methodology=False, # 禁用方法论
@@ -411,6 +413,11 @@ def main() -> None:
411
413
  choices=["normal", "thinking"],
412
414
  help="LLM type to use",
413
415
  )
416
+ parser.add_argument(
417
+ "--model_group",
418
+ type=str,
419
+ help="Model group to use, overriding config",
420
+ )
414
421
  parser.add_argument(
415
422
  "-r", "--requirement", type=str, help="Requirement to process", default=None
416
423
  )
@@ -427,7 +434,11 @@ def main() -> None:
427
434
  PrettyOutput.print(f"当前目录: {git_dir}", OutputType.INFO)
428
435
 
429
436
  try:
430
- agent = CodeAgent(llm_type=args.llm_type, need_summary=False)
437
+ agent = CodeAgent(
438
+ llm_type=args.llm_type,
439
+ model_group=args.model_group,
440
+ need_summary=False,
441
+ )
431
442
 
432
443
  # 尝试恢复会话
433
444
  if args.restore_session:
@@ -3,12 +3,13 @@ import os
3
3
  import re
4
4
  import subprocess
5
5
  import tempfile
6
- from typing import Any, Dict, List
6
+ from typing import Any, Dict, List, Optional
7
7
 
8
8
  from jarvis.jarvis_agent import Agent
9
9
  from jarvis.jarvis_code_analysis.checklists.loader import get_language_checklist
10
10
  from jarvis.jarvis_platform.registry import PlatformRegistry
11
11
  from jarvis.jarvis_tools.read_code import ReadCodeTool
12
+ from jarvis.jarvis_utils.globals import get_agent, current_agent_name
12
13
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
13
14
  from jarvis.jarvis_utils.tag import ct, ot
14
15
  from jarvis.jarvis_utils.utils import init_env, is_context_overflow
@@ -261,7 +262,9 @@ class CodeReviewTool:
261
262
  checklist = get_language_checklist(language)
262
263
  return checklist if checklist else ""
263
264
 
264
- def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
265
+ def execute(
266
+ self, args: Dict[str, Any], agent: Optional["Agent"] = None
267
+ ) -> Dict[str, Any]:
265
268
  try:
266
269
  review_type = args.get("review_type", "current").strip()
267
270
  root_dir = args.get("root_dir", ".")
@@ -570,9 +573,17 @@ class CodeReviewTool:
570
573
 
571
574
  tool_registry = ToolRegistry()
572
575
  tool_registry.dont_use_tools(["code_review"])
576
+
577
+ # Use the provided agent's model_group or get it from globals
578
+ calling_agent = agent or get_agent(current_agent_name)
579
+ model_group = None
580
+ if calling_agent and hasattr(calling_agent, "model") and calling_agent.model:
581
+ model_group = calling_agent.model.model_group
582
+
573
583
  agent = Agent(
574
584
  system_prompt=system_prompt,
575
585
  name="Code Review Agent",
586
+ model_group=model_group,
576
587
  summary_prompt=f"""<code_review_report>
577
588
  <overview>
578
589
  # 整体评估
@@ -675,7 +686,7 @@ class CodeReviewTool:
675
686
 
676
687
  try:
677
688
  # Check if content is too large
678
- is_large_content = is_context_overflow(diff_output)
689
+ is_large_content = is_context_overflow(diff_output, model_group)
679
690
 
680
691
  # Upload the file to the agent's model
681
692
  if is_large_content:
@@ -141,6 +141,47 @@
141
141
  "description": "思考操作模型名称",
142
142
  "default": "deep_seek"
143
143
  },
144
+ "JARVIS_MODEL_GROUP": {
145
+ "type": "string",
146
+ "description": "选择一个预定义的模型组"
147
+ },
148
+ "JARVIS_MODEL_GROUPS": {
149
+ "type": "array",
150
+ "description": "预定义的模型配置组",
151
+ "items": {
152
+ "type": "object",
153
+ "additionalProperties": {
154
+ "type": "object",
155
+ "properties": {
156
+ "JARVIS_PLATFORM": {
157
+ "type": "string"
158
+ },
159
+ "JARVIS_MODEL": {
160
+ "type": "string"
161
+ },
162
+ "JARVIS_THINKING_PLATFORM": {
163
+ "type": "string"
164
+ },
165
+ "JARVIS_THINKING_MODEL": {
166
+ "type": "string"
167
+ },
168
+ "JARVIS_MAX_TOKEN_COUNT": {
169
+ "type": "number"
170
+ },
171
+ "JARVIS_MAX_INPUT_TOKEN_COUNT": {
172
+ "type": "number"
173
+ },
174
+ "JARVIS_MAX_BIG_CONTENT_SIZE": {
175
+ "type": "number"
176
+ }
177
+ },
178
+ "required": [
179
+ "JARVIS_PLATFORM",
180
+ "JARVIS_MODEL"
181
+ ]
182
+ }
183
+ }
184
+ },
144
185
  "JARVIS_EXECUTE_TOOL_CONFIRM": {
145
186
  "type": "boolean",
146
187
  "description": "执行工具前是否需要确认",
@@ -16,6 +16,7 @@ from jarvis.jarvis_utils.git_utils import (
16
16
  find_git_root_and_cd,
17
17
  has_uncommitted_changes,
18
18
  )
19
+ from jarvis.jarvis_utils.globals import get_agent, current_agent_name
19
20
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
20
21
  from jarvis.jarvis_utils.tag import ct, ot
21
22
  from jarvis.jarvis_utils.utils import init_env, is_context_overflow
@@ -162,11 +163,17 @@ commit信息
162
163
  """
163
164
 
164
165
  # 获取模型并尝试上传文件
165
- platform = PlatformRegistry().get_normal_platform()
166
+ agent = get_agent(current_agent_name)
167
+ if agent:
168
+ platform = agent.model
169
+ model_group = agent.model.model_group
170
+ else:
171
+ platform = PlatformRegistry().get_normal_platform()
172
+ model_group = None
166
173
  upload_success = False
167
174
 
168
175
  # Check if content is too large
169
- is_large_content = is_context_overflow(diff)
176
+ is_large_content = is_context_overflow(diff, model_group)
170
177
 
171
178
  if is_large_content:
172
179
  if not platform.support_upload_files():
@@ -2,7 +2,7 @@
2
2
  import json
3
3
  import threading
4
4
  import time
5
- from typing import Any, Callable, Dict, List
5
+ from typing import Any, Callable, Dict, List, Optional
6
6
  from urllib.parse import parse_qs, urlencode, urljoin
7
7
 
8
8
  import requests
@@ -46,10 +46,10 @@ class SSEMcpClient(McpClient):
46
46
  self.session.headers.update(extra_headers)
47
47
 
48
48
  # SSE相关属性
49
- self.sse_response = None
50
- self.sse_thread = None
51
- self.messages_endpoint = None
52
- self.session_id = None # 从SSE连接获取的会话ID
49
+ self.sse_response: Optional[requests.Response] = None
50
+ self.sse_thread: Optional[threading.Thread] = None
51
+ self.messages_endpoint: Optional[str] = None
52
+ self.session_id: Optional[str] = None
53
53
  self.pending_requests = {} # 存储等待响应的请求 {id: Event}
54
54
  self.request_results = {} # 存储请求结果 {id: result}
55
55
  self.notification_handlers = {}
@@ -123,13 +123,15 @@ class SSEMcpClient(McpClient):
123
123
  self.sse_response = self.session.get(
124
124
  sse_url, stream=True, headers=sse_headers, timeout=30
125
125
  )
126
- self.sse_response.raise_for_status()
126
+ if self.sse_response:
127
+ self.sse_response.raise_for_status()
127
128
 
128
129
  # 启动事件处理线程
129
130
  self.sse_thread = threading.Thread(
130
131
  target=self._process_sse_events, daemon=True
131
132
  )
132
- self.sse_thread.start()
133
+ if self.sse_thread:
134
+ self.sse_thread.start()
133
135
 
134
136
  except Exception as e:
135
137
  PrettyOutput.print(f"SSE连接失败: {str(e)}", OutputType.ERROR)
@@ -2,7 +2,7 @@
2
2
  import json
3
3
  import os
4
4
  import subprocess
5
- from typing import Any, Dict, List
5
+ from typing import Any, Dict, List, Optional
6
6
 
7
7
  from jarvis.jarvis_mcp import McpClient
8
8
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
@@ -17,7 +17,7 @@ class StdioMcpClient(McpClient):
17
17
 
18
18
  def __init__(self, config: Dict[str, Any]):
19
19
  self.config = config
20
- self.process = None
20
+ self.process: Optional[subprocess.Popen] = None
21
21
  self.protocol_version = "2025-03-26" # MCP协议版本
22
22
  self._start_process()
23
23
  self._initialize()
@@ -1,7 +1,10 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  import re
3
3
  from abc import ABC, abstractmethod
4
- from typing import Generator, List, Tuple
4
+ from types import TracebackType
5
+ from typing import Generator, List, Optional, Tuple, Type
6
+
7
+ from typing_extensions import Self
5
8
 
6
9
  from rich import box # type: ignore
7
10
  from rich.live import Live # type: ignore
@@ -28,9 +31,19 @@ class BasePlatform(ABC):
28
31
  self.suppress_output = True # 添加输出控制标志
29
32
  self.web = False # 添加web属性,默认false
30
33
  self._saved = False
31
-
32
- def __del__(self):
33
- """Destroy model"""
34
+ self.model_group: Optional[str] = None
35
+
36
+ def __enter__(self) -> Self:
37
+ """Enter context manager"""
38
+ return self
39
+
40
+ def __exit__(
41
+ self,
42
+ exc_type: Optional[Type[BaseException]],
43
+ exc_val: Optional[BaseException],
44
+ exc_tb: Optional[TracebackType],
45
+ ) -> None:
46
+ """Exit context manager"""
34
47
  if not self._saved:
35
48
  self.delete_chat()
36
49
 
@@ -64,9 +77,11 @@ class BasePlatform(ABC):
64
77
 
65
78
  input_token_count = get_context_token_count(message)
66
79
 
67
- if input_token_count > get_max_input_token_count():
68
- max_chunk_size = get_max_input_token_count() - 1024 # 留出一些余量
69
- min_chunk_size = get_max_input_token_count() - 2048
80
+ if input_token_count > get_max_input_token_count(self.model_group):
81
+ max_chunk_size = (
82
+ get_max_input_token_count(self.model_group) - 1024
83
+ ) # 留出一些余量
84
+ min_chunk_size = get_max_input_token_count(self.model_group) - 2048
70
85
  inputs = split_text_into_chunks(message, max_chunk_size, min_chunk_size)
71
86
  print("📤 正在提交长上下文...")
72
87
  prefix_prompt = f"""
@@ -95,14 +110,10 @@ class BasePlatform(ABC):
95
110
  ):
96
111
  response += trunk
97
112
 
98
- print(
99
- f"📤 提交第{submit_count}部分完成,当前进度:{length}/{len(message)}"
100
- )
113
+ print(f"📤 提交第{submit_count}部分完成,当前进度:{length}/{len(message)}")
101
114
  print("✅ 提交完成")
102
115
  response += "\n" + while_true(
103
- lambda: while_success(
104
- lambda: self._chat("内容已经全部提供完毕,请根据内容继续"), 5
105
- ),
116
+ lambda: while_success(lambda: self._chat("内容已经全部提供完毕,请根据内容继续"), 5),
106
117
  5,
107
118
  )
108
119
  else:
@@ -233,6 +244,10 @@ class BasePlatform(ABC):
233
244
  """Set whether to suppress output"""
234
245
  self.suppress_output = suppress
235
246
 
247
+ def set_model_group(self, model_group: Optional[str]):
248
+ """Set model group"""
249
+ self.model_group = model_group
250
+
236
251
  def set_web(self, web: bool):
237
252
  """Set web flag"""
238
253
  self.web = web
@@ -12,6 +12,7 @@ class generate_new_tool:
12
12
  生成并注册新的Jarvis工具。该工具会在用户数据目录下创建新的工具文件,
13
13
  并自动注册到当前的工具注册表中。适用场景:1. 需要创建新的自定义工具;
14
14
  2. 扩展Jarvis功能;3. 自动化重复性操作;4. 封装特定领域的功能。
15
+ 重要提示:在编写工具代码时,应尽量将工具执行的过程和结果打印出来,方便追踪工具的执行状态。
15
16
  """
16
17
 
17
18
  parameters = {
@@ -17,7 +17,7 @@ from jarvis.jarvis_tools.base import Tool
17
17
  from jarvis.jarvis_utils.config import get_data_dir, get_tool_load_dirs
18
18
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
19
19
  from jarvis.jarvis_utils.tag import ct, ot
20
- from jarvis.jarvis_utils.utils import is_context_overflow
20
+ from jarvis.jarvis_utils.utils import is_context_overflow, daily_check_git_updates
21
21
 
22
22
  tool_call_help = f"""
23
23
  <tool_system_guide>
@@ -124,7 +124,7 @@ class ToolRegistry(OutputHandlerProtocol):
124
124
  """加载工具"""
125
125
  tools = self.get_all_tools()
126
126
  if tools:
127
- tools_prompt = "<tools_section>\n"
127
+ tools_prompt = f"{tool_call_help}\n<tools_section>\n"
128
128
  tools_prompt += " <header>## 可用工具:</header>\n"
129
129
  tools_prompt += " <tools_list>\n"
130
130
  for tool in tools:
@@ -287,16 +287,18 @@ class ToolRegistry(OutputHandlerProtocol):
287
287
 
288
288
  def _load_external_tools(self) -> None:
289
289
  """从jarvis_data/tools和配置的目录加载外部工具"""
290
- tool_dirs = [Path(get_data_dir()) / "tools"] + [
291
- Path(p) for p in get_tool_load_dirs()
292
- ]
290
+ tool_dirs = [str(Path(get_data_dir()) / "tools")] + get_tool_load_dirs()
291
+
292
+ # --- 全局每日更新检查 ---
293
+ daily_check_git_updates(tool_dirs, "tools")
293
294
 
294
295
  for tool_dir in tool_dirs:
295
- if not tool_dir.exists():
296
+ p_tool_dir = Path(tool_dir)
297
+ if not p_tool_dir.exists() or not p_tool_dir.is_dir():
296
298
  continue
297
299
 
298
300
  # 遍历目录中的所有.py文件
299
- for file_path in tool_dir.glob("*.py"):
301
+ for file_path in p_tool_dir.glob("*.py"):
300
302
  # 跳过__init__.py
301
303
  if file_path.name == "__init__.py":
302
304
  continue
@@ -717,7 +719,10 @@ class ToolRegistry(OutputHandlerProtocol):
717
719
  )
718
720
 
719
721
  # 检查内容是否过大
720
- is_large_content = is_context_overflow(output)
722
+ model_group = None
723
+ if agent_instance.model:
724
+ model_group = agent_instance.model.model_group
725
+ is_large_content = is_context_overflow(output, model_group)
721
726
 
722
727
  if is_large_content:
723
728
  # 创建临时文件
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  import os
3
3
  from functools import lru_cache
4
- from typing import Any, Dict, List
4
+ from typing import Any, Dict, List, Optional
5
5
 
6
6
  import yaml # type: ignore
7
7
 
@@ -76,24 +76,26 @@ def get_replace_map() -> dict:
76
76
  return {**BUILTIN_REPLACE_MAP, **file_map}
77
77
 
78
78
 
79
- def get_max_token_count() -> int:
79
+ def get_max_token_count(model_group_override: Optional[str] = None) -> int:
80
80
  """
81
81
  获取模型允许的最大token数量。
82
82
 
83
83
  返回:
84
84
  int: 模型能处理的最大token数量。
85
85
  """
86
- return int(GLOBAL_CONFIG_DATA.get("JARVIS_MAX_TOKEN_COUNT", "960000"))
86
+ config = _get_resolved_model_config(model_group_override)
87
+ return int(config.get("JARVIS_MAX_TOKEN_COUNT", "960000"))
87
88
 
88
89
 
89
- def get_max_input_token_count() -> int:
90
+ def get_max_input_token_count(model_group_override: Optional[str] = None) -> int:
90
91
  """
91
92
  获取模型允许的最大输入token数量。
92
93
 
93
94
  返回:
94
95
  int: 模型能处理的最大输入token数量。
95
96
  """
96
- return int(GLOBAL_CONFIG_DATA.get("JARVIS_MAX_INPUT_TOKEN_COUNT", "32000"))
97
+ config = _get_resolved_model_config(model_group_override)
98
+ return int(config.get("JARVIS_MAX_INPUT_TOKEN_COUNT", "32000"))
97
99
 
98
100
 
99
101
  def get_shell_name() -> str:
@@ -113,48 +115,94 @@ def get_shell_name() -> str:
113
115
  return os.path.basename(shell_path).lower()
114
116
 
115
117
 
116
- def get_normal_platform_name() -> str:
118
+ def _get_resolved_model_config(model_group_override: Optional[str] = None) -> Dict[str, Any]:
119
+ """
120
+ 解析并合并模型配置,处理模型组。
121
+
122
+ 优先级顺序:
123
+ 1. 单独的环境变量 (JARVIS_PLATFORM, JARVIS_MODEL, etc.)
124
+ 2. JARVIS_MODEL_GROUP 中定义的组配置
125
+ 3. 代码中的默认值
126
+
127
+ 返回:
128
+ Dict[str, Any]: 解析后的模型配置字典
129
+ """
130
+ group_config = {}
131
+ model_group_name = model_group_override or GLOBAL_CONFIG_DATA.get("JARVIS_MODEL_GROUP")
132
+ # The format is a list of single-key dicts: [{'group_name': {...}}, ...]
133
+ model_groups = GLOBAL_CONFIG_DATA.get("JARVIS_MODEL_GROUPS", [])
134
+
135
+ if model_group_name and isinstance(model_groups, list):
136
+ for group_item in model_groups:
137
+ if isinstance(group_item, dict) and model_group_name in group_item:
138
+ group_config = group_item[model_group_name]
139
+ break
140
+
141
+ # Start with group config
142
+ resolved_config = group_config.copy()
143
+
144
+ # Override with specific settings from GLOBAL_CONFIG_DATA
145
+ for key in [
146
+ "JARVIS_PLATFORM",
147
+ "JARVIS_MODEL",
148
+ "JARVIS_THINKING_PLATFORM",
149
+ "JARVIS_THINKING_MODEL",
150
+ "JARVIS_MAX_TOKEN_COUNT",
151
+ "JARVIS_MAX_INPUT_TOKEN_COUNT",
152
+ "JARVIS_MAX_BIG_CONTENT_SIZE",
153
+ ]:
154
+ if key in GLOBAL_CONFIG_DATA:
155
+ resolved_config[key] = GLOBAL_CONFIG_DATA[key]
156
+
157
+ return resolved_config
158
+
159
+
160
+ def get_normal_platform_name(model_group_override: Optional[str] = None) -> str:
117
161
  """
118
162
  获取正常操作的平台名称。
119
163
 
120
164
  返回:
121
165
  str: 平台名称,默认为'yuanbao'
122
166
  """
123
- return GLOBAL_CONFIG_DATA.get("JARVIS_PLATFORM", "yuanbao")
167
+ config = _get_resolved_model_config(model_group_override)
168
+ return config.get("JARVIS_PLATFORM", "yuanbao")
124
169
 
125
170
 
126
- def get_normal_model_name() -> str:
171
+ def get_normal_model_name(model_group_override: Optional[str] = None) -> str:
127
172
  """
128
173
  获取正常操作的模型名称。
129
174
 
130
175
  返回:
131
- str: 模型名称,默认为'deep_seek'
176
+ str: 模型名称,默认为'deep_seek_v3'
132
177
  """
133
- return GLOBAL_CONFIG_DATA.get("JARVIS_MODEL", "deep_seek_v3")
178
+ config = _get_resolved_model_config(model_group_override)
179
+ return config.get("JARVIS_MODEL", "deep_seek_v3")
134
180
 
135
181
 
136
- def get_thinking_platform_name() -> str:
182
+ def get_thinking_platform_name(model_group_override: Optional[str] = None) -> str:
137
183
  """
138
184
  获取思考操作的平台名称。
139
185
 
140
186
  返回:
141
- str: 平台名称,默认为'yuanbao'
187
+ str: 平台名称,默认为正常操作平台
142
188
  """
143
- return GLOBAL_CONFIG_DATA.get(
144
- "JARVIS_THINKING_PLATFORM", GLOBAL_CONFIG_DATA.get("JARVIS_PLATFORM", "yuanbao")
189
+ config = _get_resolved_model_config(model_group_override)
190
+ # Fallback to normal platform if thinking platform is not specified
191
+ return config.get(
192
+ "JARVIS_THINKING_PLATFORM", get_normal_platform_name(model_group_override)
145
193
  )
146
194
 
147
195
 
148
- def get_thinking_model_name() -> str:
196
+ def get_thinking_model_name(model_group_override: Optional[str] = None) -> str:
149
197
  """
150
198
  获取思考操作的模型名称。
151
199
 
152
200
  返回:
153
- str: 模型名称,默认为'deep_seek'
201
+ str: 模型名称,默认为正常操作模型
154
202
  """
155
- return GLOBAL_CONFIG_DATA.get(
156
- "JARVIS_THINKING_MODEL", GLOBAL_CONFIG_DATA.get("JARVIS_MODEL", "deep_seek")
157
- )
203
+ config = _get_resolved_model_config(model_group_override)
204
+ # Fallback to normal model if thinking model is not specified
205
+ return config.get("JARVIS_THINKING_MODEL", get_normal_model_name(model_group_override))
158
206
 
159
207
 
160
208
  def is_execute_tool_confirm() -> bool:
@@ -190,14 +238,15 @@ def get_data_dir() -> str:
190
238
  )
191
239
 
192
240
 
193
- def get_max_big_content_size() -> int:
241
+ def get_max_big_content_size(model_group_override: Optional[str] = None) -> int:
194
242
  """
195
243
  获取最大大内容大小。
196
244
 
197
245
  返回:
198
246
  int: 最大大内容大小
199
247
  """
200
- return int(GLOBAL_CONFIG_DATA.get("JARVIS_MAX_BIG_CONTENT_SIZE", "160000"))
248
+ config = _get_resolved_model_config(model_group_override)
249
+ return int(config.get("JARVIS_MAX_BIG_CONTENT_SIZE", "160000"))
201
250
 
202
251
 
203
252
  def get_pretty_output() -> bool:
@@ -240,6 +289,16 @@ def get_tool_load_dirs() -> List[str]:
240
289
  return GLOBAL_CONFIG_DATA.get("JARVIS_TOOL_LOAD_DIRS", [])
241
290
 
242
291
 
292
+ def get_methodology_dirs() -> List[str]:
293
+ """
294
+ 获取方法论加载目录。
295
+
296
+ 返回:
297
+ List[str]: 方法论加载目录列表
298
+ """
299
+ return GLOBAL_CONFIG_DATA.get("JARVIS_METHODOLOGY_DIRS", [])
300
+
301
+
243
302
  def is_print_prompt() -> bool:
244
303
  """
245
304
  获取是否打印提示。
@@ -538,12 +538,12 @@ def get_recent_commits_with_files() -> List[Dict[str, Any]]:
538
538
  return []
539
539
 
540
540
  # 解析提交信息
541
- commits = []
541
+ commits: List[Dict[str, Any]] = []
542
542
  lines = result.stdout.splitlines()
543
543
  for i in range(0, len(lines), 4):
544
544
  if i + 3 >= len(lines):
545
545
  break
546
- commit = {
546
+ commit: Dict[str, Any] = {
547
547
  "hash": lines[i],
548
548
  "message": lines[i + 1],
549
549
  "author": lines[i + 2],
@@ -11,7 +11,7 @@ import os
11
11
 
12
12
  # 全局变量:保存最后一条消息
13
13
  last_message: str = ""
14
- from typing import Any, Set
14
+ from typing import Any, Dict, Set
15
15
 
16
16
  import colorama
17
17
  from rich.console import Console
@@ -22,7 +22,7 @@ colorama.init()
22
22
  # 禁用tokenizers并行以避免多进程问题
23
23
  os.environ["TOKENIZERS_PARALLELISM"] = "false"
24
24
  # 全局代理管理
25
- global_agents: Set[str] = set()
25
+ global_agents: Dict[str, Any] = {}
26
26
  current_agent_name: str = ""
27
27
  # 表示与大模型交互的深度(>0表示正在交互)
28
28
  g_in_chat: int = 0
@@ -66,6 +66,19 @@ def make_agent_name(agent_name: str) -> str:
66
66
  return agent_name
67
67
 
68
68
 
69
+ def get_agent(agent_name: str) -> Any:
70
+ """
71
+ 获取指定名称的代理实例。
72
+
73
+ 参数:
74
+ agent_name: 代理名称
75
+
76
+ 返回:
77
+ Any: 代理实例,如果不存在则返回None
78
+ """
79
+ return global_agents.get(agent_name)
80
+
81
+
69
82
  def set_agent(agent_name: str, agent: Any) -> None:
70
83
  """
71
84
  设置当前代理并将其添加到全局代理集合中。
@@ -74,7 +87,7 @@ def set_agent(agent_name: str, agent: Any) -> None:
74
87
  agent_name: 代理名称
75
88
  agent: 代理对象
76
89
  """
77
- global_agents.add(agent_name)
90
+ global_agents[agent_name] = agent
78
91
  global current_agent_name
79
92
  current_agent_name = agent_name
80
93
 
@@ -101,7 +114,7 @@ def delete_agent(agent_name: str) -> None:
101
114
  agent_name: 要删除的代理名称
102
115
  """
103
116
  if agent_name in global_agents:
104
- global_agents.remove(agent_name)
117
+ del global_agents[agent_name]
105
118
  global current_agent_name
106
119
  current_agent_name = ""
107
120
 
@@ -173,10 +186,3 @@ def get_last_message() -> str:
173
186
  str: 最后一条消息
174
187
  """
175
188
  return last_message
176
- """
177
- 获取当前中断信号状态。
178
-
179
- 返回:
180
- int: 当前中断计数
181
- """
182
- return g_interrupt
@@ -10,14 +10,15 @@
10
10
  import json
11
11
  import os
12
12
  import tempfile
13
+ from pathlib import Path
13
14
  from typing import Any, Dict, List, Optional
14
15
 
15
16
  from jarvis.jarvis_platform.base import BasePlatform
16
17
  from jarvis.jarvis_platform.registry import PlatformRegistry
17
- from jarvis.jarvis_utils.config import get_data_dir
18
+ from jarvis.jarvis_utils.config import get_data_dir, get_methodology_dirs
19
+ from jarvis.jarvis_utils.globals import get_agent, current_agent_name
18
20
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
19
- from jarvis.jarvis_utils.utils import is_context_overflow
20
-
21
+ from jarvis.jarvis_utils.utils import is_context_overflow, daily_check_git_updates
21
22
 
22
23
  def _get_methodology_directory() -> str:
23
24
  """
@@ -37,32 +38,39 @@ def _get_methodology_directory() -> str:
37
38
 
38
39
  def _load_all_methodologies() -> Dict[str, str]:
39
40
  """
40
- 加载所有方法论文件
41
+ 从默认目录和配置的外部目录加载所有方法论文件。
41
42
 
42
43
  返回:
43
- Dict[str, str]: 方法论字典,键为问题类型,值为方法论内容
44
+ Dict[str, str]: 方法论字典,键为问题类型,值为方法论内容。
44
45
  """
45
- methodology_dir = _get_methodology_directory()
46
46
  all_methodologies = {}
47
+ methodology_dirs = [_get_methodology_directory()] + get_methodology_dirs()
47
48
 
48
- if not os.path.exists(methodology_dir):
49
- return all_methodologies
49
+ # --- 全局每日更新检查 ---
50
+ daily_check_git_updates(methodology_dirs, "methodologies")
50
51
 
51
52
  import glob
52
53
 
53
- for filepath in glob.glob(os.path.join(methodology_dir, "*.json")):
54
- try:
55
- with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
56
- methodology = json.load(f)
57
- problem_type = methodology.get("problem_type", "")
58
- content = methodology.get("content", "")
59
- if problem_type and content:
60
- all_methodologies[problem_type] = content
61
- except Exception as e:
62
- filename = os.path.basename(filepath)
63
- PrettyOutput.print(
64
- f"加载方法论文件 {filename} 失败: {str(e)}", OutputType.WARNING
65
- )
54
+ for directory in set(methodology_dirs): # Use set to avoid duplicates
55
+ if not os.path.isdir(directory):
56
+ PrettyOutput.print(f"警告: 方法论目录不存在或不是一个目录: {directory}", OutputType.WARNING)
57
+ continue
58
+
59
+ for filepath in glob.glob(os.path.join(directory, "*.json")):
60
+ try:
61
+ with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
62
+ methodology = json.load(f)
63
+ problem_type = methodology.get("problem_type", "")
64
+ content = methodology.get("content", "")
65
+ if problem_type and content:
66
+ if problem_type in all_methodologies:
67
+ PrettyOutput.print(f"警告: 方法论 '{problem_type}' 被 '{filepath}' 覆盖。", OutputType.WARNING)
68
+ all_methodologies[problem_type] = content
69
+ except Exception as e:
70
+ filename = os.path.basename(filepath)
71
+ PrettyOutput.print(
72
+ f"加载方法论文件 {filename} 失败: {str(e)}", OutputType.WARNING
73
+ )
66
74
 
67
75
  return all_methodologies
68
76
 
@@ -163,7 +171,13 @@ def load_methodology(user_input: str, tool_registery: Optional[Any] = None) -> s
163
171
  print(f"✅ 加载方法论文件完成 (共 {len(methodologies)} 个)")
164
172
 
165
173
  # 获取当前平台
166
- platform = PlatformRegistry().get_normal_platform()
174
+ agent = get_agent(current_agent_name)
175
+ if agent:
176
+ platform = agent.model
177
+ model_group = agent.model.model_group
178
+ else:
179
+ platform = PlatformRegistry().get_normal_platform()
180
+ model_group = None
167
181
  platform.set_suppress_output(False)
168
182
  if not platform:
169
183
  return ""
@@ -198,7 +212,7 @@ def load_methodology(user_input: str, tool_registery: Optional[Any] = None) -> s
198
212
  """
199
213
 
200
214
  # 检查内容是否过大
201
- is_large_content = is_context_overflow(full_content)
215
+ is_large_content = is_context_overflow(full_content, model_group)
202
216
  temp_file_path = None
203
217
 
204
218
  try:
@@ -10,7 +10,7 @@
10
10
  """
11
11
  from datetime import datetime
12
12
  from enum import Enum
13
- from typing import Optional, Tuple
13
+ from typing import Dict, Optional, Tuple, Any
14
14
 
15
15
  from pygments.lexers import guess_lexer
16
16
  from pygments.util import ClassNotFound
@@ -175,7 +175,7 @@ class PrettyOutput:
175
175
  lang: 语法高亮的语言
176
176
  traceback: 是否显示错误的回溯信息
177
177
  """
178
- styles = {
178
+ styles: Dict[OutputType, Dict[str, Any]] = {
179
179
  OutputType.SYSTEM: dict(bgcolor="#1e2b3c"),
180
180
  OutputType.CODE: dict(bgcolor="#1c2b1c"),
181
181
  OutputType.RESULT: dict(bgcolor="#1c1c2b"),
@@ -7,7 +7,8 @@ import subprocess
7
7
  import sys
8
8
  import time
9
9
  from pathlib import Path
10
- from typing import Any, Callable, Dict, Optional
10
+ from typing import Any, Callable, Dict, List, Optional
11
+ from datetime import datetime
11
12
 
12
13
  import yaml # type: ignore
13
14
 
@@ -416,9 +417,13 @@ def count_cmd_usage() -> None:
416
417
  _update_cmd_stats(sys.argv[0])
417
418
 
418
419
 
419
- def is_context_overflow(content: str) -> bool:
420
+ def is_context_overflow(
421
+ content: str, model_group_override: Optional[str] = None
422
+ ) -> bool:
420
423
  """判断文件内容是否超出上下文限制"""
421
- return get_context_token_count(content) > get_max_big_content_size()
424
+ return get_context_token_count(content) > get_max_big_content_size(
425
+ model_group_override
426
+ )
422
427
 
423
428
 
424
429
  def get_loc_stats() -> str:
@@ -475,3 +480,132 @@ def copy_to_clipboard(text: str) -> None:
475
480
  )
476
481
  except Exception as e:
477
482
  PrettyOutput.print(f"使用xclip时出错: {e}", OutputType.WARNING)
483
+
484
+
485
+ def _pull_git_repo(repo_path: Path, repo_type: str):
486
+ """对指定的git仓库执行git pull操作,并根据commit hash判断是否有更新。"""
487
+ git_dir = repo_path / ".git"
488
+ if not git_dir.is_dir():
489
+ return
490
+
491
+ PrettyOutput.print(f"正在更新{repo_type}库 '{repo_path.name}'...", OutputType.INFO)
492
+ try:
493
+ # 检查是否有远程仓库
494
+ remote_result = subprocess.run(
495
+ ["git", "remote"],
496
+ cwd=repo_path,
497
+ capture_output=True,
498
+ text=True,
499
+ check=True,
500
+ timeout=10,
501
+ )
502
+ if not remote_result.stdout.strip():
503
+ PrettyOutput.print(
504
+ f"'{repo_path.name}' 未配置远程仓库,跳过更新。",
505
+ OutputType.INFO,
506
+ )
507
+ return
508
+
509
+ # 检查git仓库状态
510
+ status_result = subprocess.run(
511
+ ["git", "status", "--porcelain"],
512
+ cwd=repo_path,
513
+ capture_output=True,
514
+ text=True,
515
+ check=True,
516
+ timeout=10,
517
+ )
518
+ if status_result.stdout:
519
+ PrettyOutput.print(
520
+ f"检测到 '{repo_path.name}' 存在未提交的更改,跳过自动更新。",
521
+ OutputType.WARNING,
522
+ )
523
+ return
524
+
525
+ # 获取更新前的commit hash
526
+ before_hash_result = subprocess.run(
527
+ ["git", "rev-parse", "HEAD"],
528
+ cwd=repo_path,
529
+ capture_output=True,
530
+ text=True,
531
+ check=True,
532
+ timeout=10,
533
+ )
534
+ before_hash = before_hash_result.stdout.strip()
535
+
536
+ # 执行 git pull
537
+ pull_result = subprocess.run(
538
+ ["git", "pull"],
539
+ cwd=repo_path,
540
+ capture_output=True,
541
+ text=True,
542
+ check=True,
543
+ timeout=60,
544
+ )
545
+
546
+ # 获取更新后的commit hash
547
+ after_hash_result = subprocess.run(
548
+ ["git", "rev-parse", "HEAD"],
549
+ cwd=repo_path,
550
+ capture_output=True,
551
+ text=True,
552
+ check=True,
553
+ timeout=10,
554
+ )
555
+ after_hash = after_hash_result.stdout.strip()
556
+
557
+ if before_hash != after_hash:
558
+ PrettyOutput.print(f"{repo_type}库 '{repo_path.name}' 已更新。", OutputType.SUCCESS)
559
+ if pull_result.stdout.strip():
560
+ PrettyOutput.print(pull_result.stdout.strip(), OutputType.INFO)
561
+ else:
562
+ PrettyOutput.print(f"{repo_type}库 '{repo_path.name}' 已是最新版本。", OutputType.INFO)
563
+
564
+ except FileNotFoundError:
565
+ PrettyOutput.print(
566
+ f"git 命令未找到,跳过更新 '{repo_path.name}'。", OutputType.WARNING
567
+ )
568
+ except subprocess.TimeoutExpired:
569
+ PrettyOutput.print(f"更新 '{repo_path.name}' 超时。", OutputType.ERROR)
570
+ except subprocess.CalledProcessError as e:
571
+ error_message = e.stderr.strip() if e.stderr else str(e)
572
+ PrettyOutput.print(
573
+ f"更新 '{repo_path.name}' 失败: {error_message}", OutputType.ERROR
574
+ )
575
+ except Exception as e:
576
+ PrettyOutput.print(
577
+ f"更新 '{repo_path.name}' 时发生未知错误: {str(e)}", OutputType.ERROR
578
+ )
579
+
580
+
581
+ def daily_check_git_updates(repo_dirs: List[str], repo_type: str):
582
+ """
583
+ 对指定的目录列表执行每日一次的git更新检查。
584
+
585
+ Args:
586
+ repo_dirs (List[str]): 需要检查的git仓库目录列表。
587
+ repo_type (str): 仓库的类型名称,例如 "工具" 或 "方法论",用于日志输出。
588
+ """
589
+ data_dir = Path(get_data_dir())
590
+ last_check_file = data_dir / f"{repo_type}_updates_last_check.txt"
591
+ should_check_for_updates = True
592
+
593
+ if last_check_file.exists():
594
+ try:
595
+ last_check_timestamp = float(last_check_file.read_text())
596
+ last_check_date = datetime.fromtimestamp(last_check_timestamp).date()
597
+ if last_check_date == datetime.now().date():
598
+ should_check_for_updates = False
599
+ except (ValueError, IOError):
600
+ pass
601
+
602
+ if should_check_for_updates:
603
+ PrettyOutput.print(f"执行每日{repo_type}库更新检查...", OutputType.INFO)
604
+ for repo_dir in repo_dirs:
605
+ p_repo_dir = Path(repo_dir)
606
+ if p_repo_dir.exists() and p_repo_dir.is_dir():
607
+ _pull_git_repo(p_repo_dir, repo_type)
608
+ try:
609
+ last_check_file.write_text(str(time.time()))
610
+ except IOError as e:
611
+ PrettyOutput.print(f"无法写入git更新检查时间戳: {e}", OutputType.WARNING)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.1.225
3
+ Version: 0.2.0
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
@@ -508,9 +508,9 @@ ENV:
508
508
  #### Kimi
509
509
  ```yaml
510
510
  JARVIS_PLATFORM: kimi
511
- JARVIS_MODEL: kimi
511
+ JARVIS_MODEL: k1.5
512
512
  JARVIS_THINKING_PLATFORM: kimi
513
- JARVIS_THINKING_MODEL: k1
513
+ JARVIS_THINKING_MODEL: k1.5-thinking
514
514
  ENV:
515
515
  KIMI_API_KEY: <Kimi API KEY>
516
516
  ```
@@ -535,19 +535,55 @@ OPENAI_API_KEY: <OpenAI API Key>
535
535
  OPENAI_API_BASE: https://api.openai.com/v1
536
536
  ```
537
537
 
538
- ### 2. 配置项说明
538
+ ### 2. 模型组配置 (高级)
539
+
540
+ 除了单独配置每个模型参数,您还可以定义和使用**模型组**来快速切换不同的模型组合。这对于需要在不同任务或平台间频繁切换的场景非常有用。
541
+
542
+ **配置示例** (`~/.jarvis/config.yaml`):
543
+
544
+ ```yaml
545
+ # 定义模型组
546
+ JARVIS_MODEL_GROUPS:
547
+ - kimi:
548
+ JARVIS_PLATFORM: kimi
549
+ JARVIS_MODEL: k1.5
550
+ JARVIS_THINKING_PLATFORM: kimi
551
+ JARVIS_THINKING_MODEL: k1.5-thinking
552
+ JARVIS_MAX_TOKEN_COUNT: 8192
553
+ - ai8:
554
+ JARVIS_PLATFORM: ai8
555
+ JARVIS_MODEL: gemini-2.5-pro
556
+ # 如果不指定思考模型,将自动使用常规模型
557
+ # JARVIS_THINKING_PLATFORM: ai8
558
+ # JARVIS_THINKING_MODEL: gemini-2.5-pro
559
+
560
+ # 选择要使用的模型组
561
+ JARVIS_MODEL_GROUP: kimi
562
+ ```
563
+
564
+ **配置优先级规则:**
565
+
566
+ Jarvis 会按照以下顺序解析模型配置,序号越小优先级越高:
567
+
568
+ 1. **独立配置**: 直接设置的 `JARVIS_PLATFORM`, `JARVIS_MODEL`, `JARVIS_THINKING_PLATFORM`, `JARVIS_THINKING_MODEL` 环境变量。这些配置会**覆盖**任何模型组中的设置。
569
+ 2. **模型组配置**: 通过 `JARVIS_MODEL_GROUP` 选中的模型组配置。
570
+ 3. **默认值**: 如果以上均未配置,则使用代码中定义的默认模型(如 `yuanbao` 和 `deep_seek_v3`)。
571
+
572
+ ### 3. 全部配置项说明
539
573
  | 变量名称 | 默认值 | 说明 |
540
574
  |----------|--------|------|
541
575
  | `ENV` | {} | 环境变量配置 |
542
- | `JARVIS_MAX_TOKEN_COUNT` | 960000 | 上下文窗口的最大token数量 |
543
- | `JARVIS_MAX_INPUT_TOKEN_COUNT` | 32000 | 输入的最大token数量 |
544
- | `JARVIS_PLATFORM` | yuanbao | 默认AI平台 |
545
- | `JARVIS_MODEL` | deep_seek_v3 | 默认模型 |
546
- | `JARVIS_THINKING_PLATFORM` | JARVIS_PLATFORM | 推理任务使用的平台 |
547
- | `JARVIS_THINKING_MODEL` | JARVIS_MODEL | 推理任务使用的模型 |
576
+ | `JARVIS_MODEL_GROUPS` | `[]` | 预定义的模型配置组列表 |
577
+ | `JARVIS_MODEL_GROUP` | `null` | 选择要激活的模型组名称 |
578
+ | `JARVIS_MAX_TOKEN_COUNT` | 960000 | 上下文窗口的最大token数量 (可被模型组覆盖) |
579
+ | `JARVIS_MAX_INPUT_TOKEN_COUNT` | 32000 | 输入的最大token数量 (可被模型组覆盖) |
580
+ | `JARVIS_PLATFORM` | yuanbao | 默认AI平台 (可被模型组覆盖) |
581
+ | `JARVIS_MODEL` | deep_seek_v3 | 默认模型 (可被模型组覆盖) |
582
+ | `JARVIS_THINKING_PLATFORM` | JARVIS_PLATFORM | 推理任务使用的平台 (可被模型组覆盖) |
583
+ | `JARVIS_THINKING_MODEL` | JARVIS_MODEL | 推理任务使用的模型 (可被模型组覆盖) |
548
584
  | `JARVIS_EXECUTE_TOOL_CONFIRM` | false | 执行工具前是否需要确认 |
549
585
  | `JARVIS_CONFIRM_BEFORE_APPLY_PATCH` | false | 应用补丁前是否需要确认 |
550
- | `JARVIS_MAX_BIG_CONTENT_SIZE` | 160000 | 最大大内容大小 |
586
+ | `JARVIS_MAX_BIG_CONTENT_SIZE` | 160000 | 最大大内容大小 (可被模型组覆盖) |
551
587
  | `JARVIS_PRETTY_OUTPUT` | false | 是否启用PrettyOutput |
552
588
  | `JARVIS_GIT_COMMIT_PROMPT` | "" | 自定义git提交信息生成提示模板 |
553
589
  | `JARVIS_PRINT_PROMPT` | false | 是否打印提示 |
@@ -1,9 +1,9 @@
1
- jarvis/__init__.py,sha256=46Ob6ZTm4a9stXblcxcvfaE4NlTYqHOyTFezByeVN_Y,75
2
- jarvis/jarvis_agent/__init__.py,sha256=mpNT4SPLYyUP3vb4zR8GM04pOej8MpnMqfkoz5ZARSQ,22412
1
+ jarvis/__init__.py,sha256=EmFCOffXrFq1m3oGpL5fp5ciwQF4OV_6X1esvw2Ukdg,73
2
+ jarvis/jarvis_agent/__init__.py,sha256=BmBbMUsCwe_0znrwxSipaKj-MuOgJTZvLbyKzBFfpic,22559
3
3
  jarvis/jarvis_agent/builtin_input_handler.py,sha256=Qs4LAr4xdKLBJpQE81YP4CkucAop86ms0iVoKa1nnso,2468
4
4
  jarvis/jarvis_agent/edit_file_handler.py,sha256=ml1o-BE2Ca1-ybPlKuhstLQYwdJag39o0_-PXTUvFaE,11646
5
- jarvis/jarvis_agent/jarvis.py,sha256=5Lkh2RbVqL_se8ZWcXxlh7XiJDhac8fxRtWmMHHO-q8,7803
6
- jarvis/jarvis_agent/main.py,sha256=W23ORF8mIxZv4GTLPuR1SlrioJLT0dLeFXrYAAMSc1A,3091
5
+ jarvis/jarvis_agent/jarvis.py,sha256=dRJWrMbZnxo5g7_5-x9IPypPYynUhMIYBVlqtlOlOb0,7969
6
+ jarvis/jarvis_agent/main.py,sha256=ufMQsv1-9wU2E3UAyu48oITwFSIBVFsUfnlhDZ7dWbU,3293
7
7
  jarvis/jarvis_agent/output_handler.py,sha256=P7oWpXBGFfOsWq7cIhS_z9crkQ19ES7qU5pM92KKjAs,1172
8
8
  jarvis/jarvis_agent/prompt_builder.py,sha256=PH1fPDVa8z_RXkoXHJFNDf8PQjUoLNLYwkh2lC__p40,1705
9
9
  jarvis/jarvis_agent/prompts.py,sha256=e8i-3kaGr96mlzL3UUhQUHFDfbJSoE4xiF9TDksNDm4,7720
@@ -12,9 +12,9 @@ jarvis/jarvis_agent/session_manager.py,sha256=DnvI9rWkVmkyO1XfKZyo9lTn4ajg4ccwzE
12
12
  jarvis/jarvis_agent/shell_input_handler.py,sha256=1IboqdxcJuoIqRpmDU10GugR9fWXUHyCEbVF4nIWbyo,1328
13
13
  jarvis/jarvis_agent/tool_executor.py,sha256=nIq-sPNgrtimtM-IHpN09cWmId8jDzWRdCFoRzXnnoo,1721
14
14
  jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- jarvis/jarvis_code_agent/code_agent.py,sha256=ZTvZ6tCVMv6nJBteLy39q0qtsg4OsvcIeg3ip7szVnc,18374
15
+ jarvis/jarvis_code_agent/code_agent.py,sha256=YQYeaFx-dlf5p6_vw7T4mmtwyqQkytlxMUWDhF2V3_Y,18659
16
16
  jarvis/jarvis_code_agent/lint.py,sha256=LZPsfyZPMo7Wm7LN4osZocuNJwZx1ojacO3MlF870x8,4009
17
- jarvis/jarvis_code_analysis/code_review.py,sha256=Huia4w1SkhxfzAk2GNC75uo3a_BcVTCDbj0rx8_t0r4,30424
17
+ jarvis/jarvis_code_analysis/code_review.py,sha256=eyezZ64ffiNC8vIHF-BZ1cF9cTnk1NdpuUXfoa-jWpc,30971
18
18
  jarvis/jarvis_code_analysis/checklists/__init__.py,sha256=LIXAYa1sW3l7foP6kohLWnE98I_EQ0T7z5bYKHq6rJA,78
19
19
  jarvis/jarvis_code_analysis/checklists/c_cpp.py,sha256=9t62bMqs6qTkFSio4SKkj88qyb5ZubWrw3MxJBQ4X1A,1317
20
20
  jarvis/jarvis_code_analysis/checklists/csharp.py,sha256=ShPXrl2_UPAnGaCHAG2wLl90COG3HK2XCSr1UK2dxN4,2420
@@ -35,23 +35,23 @@ jarvis/jarvis_code_analysis/checklists/shell.py,sha256=aRFYhQQvTgbYd-uY5pc8UHIUA
35
35
  jarvis/jarvis_code_analysis/checklists/sql.py,sha256=vR0T6qC7b4dURjJVAd7kSVxyvZEQXPG1Jqc2sNTGp5c,2355
36
36
  jarvis/jarvis_code_analysis/checklists/swift.py,sha256=TPx4I6Gupvs6tSerRKmTSKEPQpOLEbH2Y7LXg1uBgxc,2566
37
37
  jarvis/jarvis_code_analysis/checklists/web.py,sha256=25gGD7pDadZQybNFvALYxWvK0VRjGQb1NVJQElwjyk0,3943
38
- jarvis/jarvis_data/config_schema.json,sha256=uuDN-25NJRnKfb6KuuqxOnfRGMphkKQbjxfu0Me6pAI,7494
38
+ jarvis/jarvis_data/config_schema.json,sha256=XpQ7aaHMW-YCuFrnaAEjMWrnv6a8B7MqGjm2XgrvtgQ,8573
39
39
  jarvis/jarvis_data/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4,sha256=Ijkht27pm96ZW3_3OFE-7xAPtR0YyTWXoRO8_-hlsqc,1681126
40
40
  jarvis/jarvis_git_details/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  jarvis/jarvis_git_details/main.py,sha256=DE1DcX-1lvUsb_K-FExpHs3NBRmo5KZb53PGa8QFBOc,8875
42
42
  jarvis/jarvis_git_squash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
43
  jarvis/jarvis_git_squash/main.py,sha256=2nwX-Ghphn97Ua0SXPJIxix-rgm_Z9KRkrovjpSklUk,2311
44
- jarvis/jarvis_git_utils/git_commiter.py,sha256=erZ3wNJuaEgHlKTaYv0UKargG_Yl9OnssTIcErEAdtw,12472
44
+ jarvis/jarvis_git_utils/git_commiter.py,sha256=Yir26RyvoToTmkeh1-cFnG3LE3fH7z2njPOK3FIpQDc,12801
45
45
  jarvis/jarvis_mcp/__init__.py,sha256=OPMtjD-uq9xAaKCRIDyKIosaFfBe1GBPu1az-mQ0rVM,2048
46
- jarvis/jarvis_mcp/sse_mcp_client.py,sha256=-3Qy1LyqgHswoc6YbadVRG3ias2op7lUp7Ne2-QUKBM,22474
47
- jarvis/jarvis_mcp/stdio_mcp_client.py,sha256=armvgyHAv-AxF5lqiK-TbVLzg3XgSCwmTdWmxBSTLRk,11248
46
+ jarvis/jarvis_mcp/sse_mcp_client.py,sha256=AhYLPQb0mE9-6ZQw1JesRNyEy0esJumNEFb5LyzyIn0,22612
47
+ jarvis/jarvis_mcp/stdio_mcp_client.py,sha256=APYUksYKlMx7AVNODKOLrTkKZPnp4kqTQIYIuNDDKko,11286
48
48
  jarvis/jarvis_mcp/streamable_mcp_client.py,sha256=1OZpsG82U2MLbGuojllJAblFUAMmp1N0i5fsKM4n5Ts,14453
49
49
  jarvis/jarvis_methodology/main.py,sha256=-PqsWvtpUJkkhiGgV-1JegEnEZBmv8SHnNMNNm_-QQc,11720
50
50
  jarvis/jarvis_multi_agent/__init__.py,sha256=efB04nWPRl4EOD64RThqQ6w78GZc2t0GGisX2wwTP8I,5949
51
51
  jarvis/jarvis_multi_agent/main.py,sha256=h7VUSwoPrES0XTK8z5kt3XLX1mmcm8UEuFEHQOUWPH4,1696
52
52
  jarvis/jarvis_platform/__init__.py,sha256=WLQHSiE87PPket2M50_hHzjdMIgPIBx2VF8JfB_NNRk,105
53
53
  jarvis/jarvis_platform/ai8.py,sha256=yi7xG8ld4Yrf7drz-uu_JT_XCGYRB0obhygt-jKik8o,10871
54
- jarvis/jarvis_platform/base.py,sha256=-XegiAS8G_nzwsWPOVEAQ2iTxE33fxu5-TWV4c3Pz-g,8981
54
+ jarvis/jarvis_platform/base.py,sha256=cfeYB6ldfQH1tz1rroQpmJTLAw8KByKS74qun0pqE1c,9498
55
55
  jarvis/jarvis_platform/human.py,sha256=cSN8Lqf0ts2_pPfS2_v7PaWxQKqcW_3bSmhRTHey7Qo,4674
56
56
  jarvis/jarvis_platform/kimi.py,sha256=dn_P4EEZvWWCPS67MDbWStsP7n3MN4-Rrc6R7GhJyEg,15436
57
57
  jarvis/jarvis_platform/openai.py,sha256=ccGqsU2cFfd5324P7SH1tSmFABpvto8fytmxQGkr3BA,6412
@@ -79,11 +79,11 @@ jarvis/jarvis_tools/base.py,sha256=tFVmK6ppsImW2BzHZmrNmMRiOJdW-4aZP6Me3VxdYcA,1
79
79
  jarvis/jarvis_tools/edit_file.py,sha256=hM345E9rxS-EkqCZpwwizL6fmPdTadtB798tEO5Ce3g,10417
80
80
  jarvis/jarvis_tools/execute_script.py,sha256=gMarE5yCCSPU6Dp6HlcL2KT-2xCzR-1p-oQNlYOJK58,6157
81
81
  jarvis/jarvis_tools/file_analyzer.py,sha256=aVe1jBSp0YmlypihxrGADJpYrU_7CxDETxGUNySuSlI,4044
82
- jarvis/jarvis_tools/generate_new_tool.py,sha256=2YAs8DC7fJnxOkjSmhmSAwqSpBlicVhYc06WZ8YVBls,7679
82
+ jarvis/jarvis_tools/generate_new_tool.py,sha256=ppMRuTYUZ0c02rHo7xi8DCGiDVPZTANVp9nS7bvkqqo,7819
83
83
  jarvis/jarvis_tools/methodology.py,sha256=_K4GIDUodGEma3SvNRo7Qs5rliijgNespVLyAPN35JU,5233
84
84
  jarvis/jarvis_tools/read_code.py,sha256=EnI-R-5HyIQYhMD391nZWXHIuHHBF-OJIRE0QpLcPX4,6417
85
85
  jarvis/jarvis_tools/read_webpage.py,sha256=NmDUboVZd4CGHBPRFK6dp3uqVhuGopW1bOi3TcaLDF4,2092
86
- jarvis/jarvis_tools/registry.py,sha256=Lfp6UcEw-Gbva-7OUTHOBrT9xYwrGrolvjaSpYhWFwU,26435
86
+ jarvis/jarvis_tools/registry.py,sha256=3SMzVM9rhI9Gl8EdI13_NOHBxwygueqw-nUcCi6AgRM,26754
87
87
  jarvis/jarvis_tools/rewrite_file.py,sha256=eG_WKg6cVAXmuGwUqlWkcuyay5S8DOzEi8vZCmX3O8w,7255
88
88
  jarvis/jarvis_tools/search_web.py,sha256=DDAPjYWTFaF85zsnhJ6VNDSc1BcY8EHus5ymKP9nnPs,5703
89
89
  jarvis/jarvis_tools/virtual_tty.py,sha256=KKr3jpvQWWMPr2o40hlmN6fuXJCN8H4_ma5QU40Citc,16089
@@ -91,20 +91,20 @@ jarvis/jarvis_tools/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
91
91
  jarvis/jarvis_tools/cli/main.py,sha256=Mg6TQDxMdzB1Ua1UrZ2EE-uQWsbaeojWaEGHJp2HimA,6375
92
92
  jarvis/jarvis_utils/__init__.py,sha256=67h0ldisGlh3oK4DAeNEL2Bl_VsI3tSmfclasyVlueM,850
93
93
  jarvis/jarvis_utils/builtin_replace_map.py,sha256=4BurljGuiG_I93EBs7mlFlPm9wYC_4CmdTG5tQWpF6g,1712
94
- jarvis/jarvis_utils/config.py,sha256=eTarDAeBdFZx2jX4KQrzanEu4W6hpS5Cw1DHmiB5nN0,8247
94
+ jarvis/jarvis_utils/config.py,sha256=YcPGjCSJ2_2CKtlY8ecyqaovKVb65XcQ5WNizjwmdVs,10689
95
95
  jarvis/jarvis_utils/embedding.py,sha256=oEOEM2qf16DMYwPsQe6srET9BknyjOdY2ef0jsp3Or8,2714
96
96
  jarvis/jarvis_utils/file_processors.py,sha256=XiM248SHS7lLgQDCbORVFWqinbVDUawYxWDOsLXDxP8,3043
97
- jarvis/jarvis_utils/git_utils.py,sha256=EpyS8AvvK9M9WnkObtQsU2gXq45PnY-WJo2c4kMtyFM,21702
98
- jarvis/jarvis_utils/globals.py,sha256=WzZh_acNfHJj1LDulhyLQ7cojksBy0gdrITe0vH1XA0,3901
97
+ jarvis/jarvis_utils/git_utils.py,sha256=_b4-5uWOTVFjAB48QbRJNBR7PTD_jzi7-5V5M_wjXFo,21740
98
+ jarvis/jarvis_utils/globals.py,sha256=QKeiiWhUlu9HE7SzAn0lKaeaXQF1uhmLXPZTeLKyGPQ,4048
99
99
  jarvis/jarvis_utils/http.py,sha256=Uqt1kcz0HWnAfXHHi1fNGwLb2lcVUqpbrG2Uk_-kcIU,4882
100
100
  jarvis/jarvis_utils/input.py,sha256=V2w3xV0MO73c4Y4XY_yy9jVNg7MmN76FmAnpKRiJUog,9160
101
- jarvis/jarvis_utils/methodology.py,sha256=-cvM6pwgJK7BXCYg2uVjIId_j3v5RUh2z2PBcK_2vj4,8155
102
- jarvis/jarvis_utils/output.py,sha256=PRCgudPOB8gMEP3u-g0FGD2c6tBgJhLXUMqNPglfjV8,10813
101
+ jarvis/jarvis_utils/methodology.py,sha256=V2Y0mbamrWBhhCK-3foAM1hKewOEcIDcXO-Sv_AU-kQ,9106
102
+ jarvis/jarvis_utils/output.py,sha256=2QMpzb8ZOysQ6HHsRjRzjgUnNXaFGkIiZ_qElPKLbsA,10858
103
103
  jarvis/jarvis_utils/tag.py,sha256=f211opbbbTcSyzCDwuIK_oCnKhXPNK-RknYyGzY1yD0,431
104
- jarvis/jarvis_utils/utils.py,sha256=OXZ57qTB3dY5e_V6lWZRivYu1cMT1e2VftW7AQBd2X0,15295
105
- jarvis_ai_assistant-0.1.225.dist-info/licenses/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
106
- jarvis_ai_assistant-0.1.225.dist-info/METADATA,sha256=s60vmDTdhXx9eGKHz22DIMFUqjqZF_G-r9PwzApQJr4,24094
107
- jarvis_ai_assistant-0.1.225.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
108
- jarvis_ai_assistant-0.1.225.dist-info/entry_points.txt,sha256=JXK_n-d9HZ_RLz959CvpK5-UPOCwssn5oAH8dAHuebA,1277
109
- jarvis_ai_assistant-0.1.225.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
110
- jarvis_ai_assistant-0.1.225.dist-info/RECORD,,
104
+ jarvis/jarvis_utils/utils.py,sha256=G6UuiBrPlWLpau1LbSGStrlAHCHG8JufINLD_bwtjTE,20006
105
+ jarvis_ai_assistant-0.2.0.dist-info/licenses/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
106
+ jarvis_ai_assistant-0.2.0.dist-info/METADATA,sha256=ddh41XdsU955MHnmlVF1YhXW5D2oYZK-M7ZsTUqVMAs,25713
107
+ jarvis_ai_assistant-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
108
+ jarvis_ai_assistant-0.2.0.dist-info/entry_points.txt,sha256=JXK_n-d9HZ_RLz959CvpK5-UPOCwssn5oAH8dAHuebA,1277
109
+ jarvis_ai_assistant-0.2.0.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
110
+ jarvis_ai_assistant-0.2.0.dist-info/RECORD,,