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 +1 -1
- jarvis/jarvis_agent/__init__.py +8 -5
- jarvis/jarvis_agent/jarvis.py +6 -0
- jarvis/jarvis_agent/main.py +7 -0
- jarvis/jarvis_code_agent/code_agent.py +12 -1
- jarvis/jarvis_code_analysis/code_review.py +14 -3
- jarvis/jarvis_data/config_schema.json +41 -0
- jarvis/jarvis_git_utils/git_commiter.py +9 -2
- jarvis/jarvis_mcp/sse_mcp_client.py +9 -7
- jarvis/jarvis_mcp/stdio_mcp_client.py +2 -2
- jarvis/jarvis_platform/base.py +28 -13
- jarvis/jarvis_tools/generate_new_tool.py +1 -0
- jarvis/jarvis_tools/registry.py +13 -8
- jarvis/jarvis_utils/config.py +80 -21
- jarvis/jarvis_utils/git_utils.py +2 -2
- jarvis/jarvis_utils/globals.py +17 -11
- jarvis/jarvis_utils/methodology.py +37 -23
- jarvis/jarvis_utils/output.py +2 -2
- jarvis/jarvis_utils/utils.py +137 -3
- {jarvis_ai_assistant-0.1.225.dist-info → jarvis_ai_assistant-0.2.0.dist-info}/METADATA +47 -11
- {jarvis_ai_assistant-0.1.225.dist-info → jarvis_ai_assistant-0.2.0.dist-info}/RECORD +25 -25
- {jarvis_ai_assistant-0.1.225.dist-info → jarvis_ai_assistant-0.2.0.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.225.dist-info → jarvis_ai_assistant-0.2.0.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.225.dist-info → jarvis_ai_assistant-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.225.dist-info → jarvis_ai_assistant-0.2.0.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
jarvis/jarvis_agent/__init__.py
CHANGED
@@ -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
|
|
jarvis/jarvis_agent/jarvis.py
CHANGED
@@ -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,
|
jarvis/jarvis_agent/main.py
CHANGED
@@ -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(
|
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(
|
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
|
-
|
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
|
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
|
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
|
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()
|
jarvis/jarvis_platform/base.py
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
import re
|
3
3
|
from abc import ABC, abstractmethod
|
4
|
-
from
|
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
|
-
|
33
|
-
|
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 =
|
69
|
-
|
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
|
jarvis/jarvis_tools/registry.py
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
# 创建临时文件
|
jarvis/jarvis_utils/config.py
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
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
|
-
|
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: 模型名称,默认为'
|
176
|
+
str: 模型名称,默认为'deep_seek_v3'
|
132
177
|
"""
|
133
|
-
|
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:
|
187
|
+
str: 平台名称,默认为正常操作平台
|
142
188
|
"""
|
143
|
-
|
144
|
-
|
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:
|
201
|
+
str: 模型名称,默认为正常操作模型
|
154
202
|
"""
|
155
|
-
|
156
|
-
|
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
|
-
|
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
|
获取是否打印提示。
|
jarvis/jarvis_utils/git_utils.py
CHANGED
@@ -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],
|
jarvis/jarvis_utils/globals.py
CHANGED
@@ -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:
|
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
|
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
|
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
|
-
|
49
|
-
|
49
|
+
# --- 全局每日更新检查 ---
|
50
|
+
daily_check_git_updates(methodology_dirs, "methodologies")
|
50
51
|
|
51
52
|
import glob
|
52
53
|
|
53
|
-
for
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
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:
|
jarvis/jarvis_utils/output.py
CHANGED
@@ -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"),
|
jarvis/jarvis_utils/utils.py
CHANGED
@@ -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(
|
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.
|
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:
|
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
|
-
| `
|
543
|
-
| `
|
544
|
-
| `
|
545
|
-
| `
|
546
|
-
| `
|
547
|
-
| `
|
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=
|
2
|
-
jarvis/jarvis_agent/__init__.py,sha256=
|
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=
|
6
|
-
jarvis/jarvis_agent/main.py,sha256=
|
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=
|
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=
|
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=
|
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=
|
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
|
47
|
-
jarvis/jarvis_mcp/stdio_mcp_client.py,sha256=
|
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
|
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=
|
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=
|
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=
|
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=
|
98
|
-
jarvis/jarvis_utils/globals.py,sha256=
|
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
|
102
|
-
jarvis/jarvis_utils/output.py,sha256=
|
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=
|
105
|
-
jarvis_ai_assistant-0.
|
106
|
-
jarvis_ai_assistant-0.
|
107
|
-
jarvis_ai_assistant-0.
|
108
|
-
jarvis_ai_assistant-0.
|
109
|
-
jarvis_ai_assistant-0.
|
110
|
-
jarvis_ai_assistant-0.
|
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,,
|
File without changes
|
{jarvis_ai_assistant-0.1.225.dist-info → jarvis_ai_assistant-0.2.0.dist-info}/entry_points.txt
RENAMED
File without changes
|
{jarvis_ai_assistant-0.1.225.dist-info → jarvis_ai_assistant-0.2.0.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
File without changes
|