jarvis-ai-assistant 0.1.126__py3-none-any.whl → 0.1.129__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.
Potentially problematic release.
This version of jarvis-ai-assistant might be problematic. Click here for more details.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +108 -95
- jarvis/jarvis_agent/main.py +77 -0
- jarvis/jarvis_code_agent/builtin_input_handler.py +43 -0
- jarvis/jarvis_code_agent/code_agent.py +17 -81
- jarvis/jarvis_code_agent/file_input_handler.py +88 -0
- jarvis/jarvis_code_agent/patch.py +142 -114
- jarvis/jarvis_code_agent/shell_input_handler.py +8 -2
- jarvis/jarvis_codebase/main.py +240 -213
- jarvis/jarvis_dev/main.py +4 -3
- jarvis/jarvis_multi_agent/__init__.py +51 -40
- jarvis/jarvis_platform/base.py +6 -5
- jarvis/jarvis_platform_manager/main.py +1 -1
- jarvis/jarvis_rag/main.py +250 -186
- jarvis/jarvis_smart_shell/main.py +0 -1
- jarvis/jarvis_tools/ask_codebase.py +4 -3
- jarvis/jarvis_tools/chdir.py +22 -22
- jarvis/jarvis_tools/code_review.py +38 -33
- jarvis/jarvis_tools/execute_shell.py +0 -3
- jarvis/jarvis_tools/file_operation.py +56 -55
- jarvis/jarvis_tools/git_commiter.py +60 -50
- jarvis/jarvis_tools/read_code.py +143 -0
- jarvis/jarvis_tools/read_webpage.py +50 -30
- jarvis/jarvis_tools/registry.py +4 -21
- jarvis/jarvis_tools/search_web.py +61 -36
- jarvis/jarvis_tools/tool_generator.py +78 -36
- jarvis/jarvis_utils/__init__.py +17 -17
- jarvis/jarvis_utils/config.py +87 -51
- jarvis/jarvis_utils/embedding.py +49 -48
- jarvis/jarvis_utils/git_utils.py +34 -34
- jarvis/jarvis_utils/globals.py +26 -26
- jarvis/jarvis_utils/input.py +61 -45
- jarvis/jarvis_utils/methodology.py +94 -76
- jarvis/jarvis_utils/output.py +63 -62
- jarvis/jarvis_utils/utils.py +2 -2
- {jarvis_ai_assistant-0.1.126.dist-info → jarvis_ai_assistant-0.1.129.dist-info}/METADATA +1 -1
- jarvis_ai_assistant-0.1.129.dist-info/RECORD +78 -0
- {jarvis_ai_assistant-0.1.126.dist-info → jarvis_ai_assistant-0.1.129.dist-info}/entry_points.txt +2 -0
- jarvis_ai_assistant-0.1.126.dist-info/RECORD +0 -74
- {jarvis_ai_assistant-0.1.126.dist-info → jarvis_ai_assistant-0.1.129.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.126.dist-info → jarvis_ai_assistant-0.1.129.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.126.dist-info → jarvis_ai_assistant-0.1.129.dist-info}/top_level.txt +0 -0
jarvis/jarvis_utils/config.py
CHANGED
|
@@ -1,138 +1,174 @@
|
|
|
1
1
|
import os
|
|
2
2
|
"""
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
3
|
+
配置管理模块
|
|
4
|
+
该模块提供了获取Jarvis系统各种配置设置的函数。
|
|
5
|
+
所有配置都从环境变量中读取,带有回退默认值。
|
|
6
|
+
该模块组织为以下几个类别:
|
|
7
|
+
- 系统配置
|
|
8
|
+
- 模型配置
|
|
9
|
+
- 执行配置
|
|
10
|
+
- 文本处理配置
|
|
11
11
|
"""
|
|
12
12
|
def get_max_token_count() -> int:
|
|
13
13
|
"""
|
|
14
|
-
|
|
14
|
+
获取API请求的最大token数量。
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
int:
|
|
16
|
+
返回:
|
|
17
|
+
int: 最大token数量,默认为131072(128k)
|
|
18
18
|
"""
|
|
19
19
|
return int(os.getenv('JARVIS_MAX_TOKEN_COUNT', '131072')) # 默认128k
|
|
20
20
|
|
|
21
21
|
def get_thread_count() -> int:
|
|
22
22
|
"""
|
|
23
|
-
|
|
23
|
+
获取用于并行处理的线程数。
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
int:
|
|
25
|
+
返回:
|
|
26
|
+
int: 线程数,默认为1
|
|
27
27
|
"""
|
|
28
28
|
return int(os.getenv('JARVIS_THREAD_COUNT', '1'))
|
|
29
29
|
def dont_use_local_model() -> bool:
|
|
30
30
|
"""
|
|
31
|
-
|
|
31
|
+
检查是否应避免使用本地模型。
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
bool: True
|
|
33
|
+
返回:
|
|
34
|
+
bool: 如果不使用本地模型则返回True,默认为False
|
|
35
35
|
"""
|
|
36
36
|
return os.getenv('JARVIS_DONT_USE_LOCAL_MODEL', 'false') == 'true'
|
|
37
37
|
|
|
38
38
|
def is_auto_complete() -> bool:
|
|
39
39
|
"""
|
|
40
|
-
|
|
40
|
+
检查是否启用了自动补全功能。
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
bool: True
|
|
42
|
+
返回:
|
|
43
|
+
bool: 如果启用了自动补全则返回True,默认为False
|
|
44
44
|
"""
|
|
45
45
|
return os.getenv('JARVIS_AUTO_COMPLETE', 'false') == 'true'
|
|
46
46
|
|
|
47
47
|
def is_use_methodology() -> bool:
|
|
48
48
|
"""
|
|
49
|
-
|
|
49
|
+
检查是否应使用方法论。
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
bool: True
|
|
51
|
+
返回:
|
|
52
|
+
bool: 如果使用方法论则返回True,默认为True
|
|
53
53
|
"""
|
|
54
54
|
return os.getenv('JARVIS_USE_METHODOLOGY', 'true') == 'true'
|
|
55
55
|
def is_record_methodology() -> bool:
|
|
56
56
|
"""
|
|
57
|
-
|
|
57
|
+
检查是否应记录方法论。
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
bool: True
|
|
59
|
+
返回:
|
|
60
|
+
bool: 如果记录方法论则返回True,默认为True
|
|
61
61
|
"""
|
|
62
62
|
return os.getenv('JARVIS_RECORD_METHODOLOGY', 'true') == 'true'
|
|
63
63
|
def is_need_summary() -> bool:
|
|
64
64
|
"""
|
|
65
|
-
|
|
65
|
+
检查是否需要生成摘要。
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
bool: True
|
|
67
|
+
返回:
|
|
68
|
+
bool: 如果需要摘要则返回True,默认为True
|
|
69
69
|
"""
|
|
70
70
|
return os.getenv('JARVIS_NEED_SUMMARY', 'true') == 'true'
|
|
71
71
|
def get_min_paragraph_length() -> int:
|
|
72
72
|
"""
|
|
73
|
-
|
|
73
|
+
获取文本处理的最小段落长度。
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
int:
|
|
75
|
+
返回:
|
|
76
|
+
int: 最小字符长度,默认为50
|
|
77
77
|
"""
|
|
78
78
|
return int(os.getenv('JARVIS_MIN_PARAGRAPH_LENGTH', '50'))
|
|
79
79
|
def get_max_paragraph_length() -> int:
|
|
80
80
|
"""
|
|
81
|
-
|
|
81
|
+
获取文本处理的最大段落长度。
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
int:
|
|
83
|
+
返回:
|
|
84
|
+
int: 最大字符长度,默认为12800
|
|
85
85
|
"""
|
|
86
86
|
return int(os.getenv('JARVIS_MAX_PARAGRAPH_LENGTH', '12800'))
|
|
87
87
|
def get_shell_name() -> str:
|
|
88
88
|
"""
|
|
89
|
-
|
|
89
|
+
获取系统shell名称。
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
str: Shell
|
|
91
|
+
返回:
|
|
92
|
+
str: Shell名称(例如bash, zsh),默认为bash
|
|
93
93
|
"""
|
|
94
94
|
return os.getenv('SHELL', 'bash')
|
|
95
95
|
def get_normal_platform_name() -> str:
|
|
96
96
|
"""
|
|
97
|
-
|
|
97
|
+
获取正常操作的平台名称。
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
str:
|
|
99
|
+
返回:
|
|
100
|
+
str: 平台名称,默认为'kimi'
|
|
101
101
|
"""
|
|
102
102
|
return os.getenv('JARVIS_PLATFORM', 'kimi')
|
|
103
103
|
def get_normal_model_name() -> str:
|
|
104
104
|
"""
|
|
105
|
-
|
|
105
|
+
获取正常操作的模型名称。
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
str:
|
|
107
|
+
返回:
|
|
108
|
+
str: 模型名称,默认为'kimi'
|
|
109
109
|
"""
|
|
110
110
|
return os.getenv('JARVIS_MODEL', 'kimi')
|
|
111
111
|
def get_codegen_platform_name() -> str:
|
|
112
|
+
"""
|
|
113
|
+
获取代码生成的平台名称。
|
|
114
|
+
|
|
115
|
+
返回:
|
|
116
|
+
str: 平台名称,默认为'kimi'
|
|
117
|
+
"""
|
|
112
118
|
return os.getenv('JARVIS_CODEGEN_PLATFORM', os.getenv('JARVIS_PLATFORM', 'kimi'))
|
|
113
119
|
def get_codegen_model_name() -> str:
|
|
120
|
+
"""
|
|
121
|
+
获取代码生成的模型名称。
|
|
122
|
+
|
|
123
|
+
返回:
|
|
124
|
+
str: 模型名称,默认为'kimi'
|
|
125
|
+
"""
|
|
114
126
|
return os.getenv('JARVIS_CODEGEN_MODEL', os.getenv('JARVIS_MODEL', 'kimi'))
|
|
115
127
|
def get_thinking_platform_name() -> str:
|
|
128
|
+
"""
|
|
129
|
+
获取思考操作的平台名称。
|
|
130
|
+
|
|
131
|
+
返回:
|
|
132
|
+
str: 平台名称,默认为'kimi'
|
|
133
|
+
"""
|
|
116
134
|
return os.getenv('JARVIS_THINKING_PLATFORM', os.getenv('JARVIS_PLATFORM', 'kimi'))
|
|
117
135
|
def get_thinking_model_name() -> str:
|
|
136
|
+
"""
|
|
137
|
+
获取思考操作的模型名称。
|
|
138
|
+
|
|
139
|
+
返回:
|
|
140
|
+
str: 模型名称,默认为'kimi'
|
|
141
|
+
"""
|
|
118
142
|
return os.getenv('JARVIS_THINKING_MODEL', os.getenv('JARVIS_MODEL', 'kimi'))
|
|
119
143
|
def get_cheap_platform_name() -> str:
|
|
144
|
+
"""
|
|
145
|
+
获取低成本操作的平台名称。
|
|
146
|
+
|
|
147
|
+
返回:
|
|
148
|
+
str: 平台名称,默认为'kimi'
|
|
149
|
+
"""
|
|
120
150
|
return os.getenv('JARVIS_CHEAP_PLATFORM', os.getenv('JARVIS_PLATFORM', 'kimi'))
|
|
121
151
|
def get_cheap_model_name() -> str:
|
|
152
|
+
"""
|
|
153
|
+
获取低成本操作的模型名称。
|
|
154
|
+
|
|
155
|
+
返回:
|
|
156
|
+
str: 模型名称,默认为'kimi'
|
|
157
|
+
"""
|
|
122
158
|
return os.getenv('JARVIS_CHEAP_MODEL', os.getenv('JARVIS_MODEL', 'kimi'))
|
|
123
159
|
def is_execute_tool_confirm() -> bool:
|
|
124
160
|
"""
|
|
125
|
-
|
|
161
|
+
检查工具执行是否需要确认。
|
|
126
162
|
|
|
127
|
-
|
|
128
|
-
bool: True
|
|
163
|
+
返回:
|
|
164
|
+
bool: 如果需要确认则返回True,默认为False
|
|
129
165
|
"""
|
|
130
166
|
return os.getenv('JARVIS_EXECUTE_TOOL_CONFIRM', 'false') == 'true'
|
|
131
167
|
def is_confirm_before_apply_patch() -> bool:
|
|
132
168
|
"""
|
|
133
|
-
|
|
169
|
+
检查应用补丁前是否需要确认。
|
|
134
170
|
|
|
135
|
-
|
|
136
|
-
bool: True
|
|
171
|
+
返回:
|
|
172
|
+
bool: 如果需要确认则返回True,默认为False
|
|
137
173
|
"""
|
|
138
|
-
return os.getenv('JARVIS_CONFIRM_BEFORE_APPLY_PATCH', 'false') == 'true'
|
|
174
|
+
return os.getenv('JARVIS_CONFIRM_BEFORE_APPLY_PATCH', 'false') == 'true'
|
jarvis/jarvis_utils/embedding.py
CHANGED
|
@@ -6,35 +6,32 @@ from transformers import AutoTokenizer, AutoModelForSequenceClassification
|
|
|
6
6
|
from typing import List, Any, Tuple
|
|
7
7
|
from jarvis.jarvis_utils.output import PrettyOutput, OutputType
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
9
|
def get_context_token_count(text: str) -> int:
|
|
13
|
-
"""
|
|
10
|
+
"""使用分词器获取文本的token数量。
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
text:
|
|
12
|
+
参数:
|
|
13
|
+
text: 要计算token的输入文本
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
int:
|
|
15
|
+
返回:
|
|
16
|
+
int: 文本中的token数量
|
|
20
17
|
"""
|
|
21
18
|
try:
|
|
22
|
-
#
|
|
19
|
+
# 使用擅长处理通用文本的快速分词器
|
|
23
20
|
tokenizer = load_tokenizer()
|
|
24
21
|
chunks = split_text_into_chunks(text, 512)
|
|
25
22
|
return sum([len(tokenizer.encode(chunk)) for chunk in chunks]) # type: ignore
|
|
26
23
|
|
|
27
24
|
except Exception as e:
|
|
28
25
|
PrettyOutput.print(f"计算token失败: {str(e)}", OutputType.WARNING)
|
|
29
|
-
#
|
|
30
|
-
return len(text) // 4 #
|
|
26
|
+
# 回退到基于字符的粗略估计
|
|
27
|
+
return len(text) // 4 # 每个token大约4个字符的粗略估计
|
|
31
28
|
|
|
32
29
|
def load_embedding_model() -> SentenceTransformer:
|
|
33
30
|
"""
|
|
34
|
-
|
|
31
|
+
加载句子嵌入模型。
|
|
35
32
|
|
|
36
|
-
|
|
37
|
-
SentenceTransformer:
|
|
33
|
+
返回:
|
|
34
|
+
SentenceTransformer: 加载的嵌入模型
|
|
38
35
|
"""
|
|
39
36
|
model_name = "BAAI/bge-m3"
|
|
40
37
|
cache_dir = os.path.expanduser("~/.cache/huggingface/hub")
|
|
@@ -53,31 +50,33 @@ def load_embedding_model() -> SentenceTransformer:
|
|
|
53
50
|
)
|
|
54
51
|
|
|
55
52
|
return embedding_model
|
|
53
|
+
|
|
56
54
|
def get_embedding(embedding_model: Any, text: str) -> np.ndarray:
|
|
57
55
|
"""
|
|
58
|
-
|
|
56
|
+
为给定文本生成嵌入向量。
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
embedding_model:
|
|
62
|
-
text:
|
|
58
|
+
参数:
|
|
59
|
+
embedding_model: 使用的嵌入模型
|
|
60
|
+
text: 要嵌入的输入文本
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
np.ndarray:
|
|
62
|
+
返回:
|
|
63
|
+
np.ndarray: 嵌入向量
|
|
66
64
|
"""
|
|
67
65
|
embedding = embedding_model.encode(text,
|
|
68
66
|
normalize_embeddings=True,
|
|
69
67
|
show_progress_bar=False)
|
|
70
68
|
return np.array(embedding, dtype=np.float32)
|
|
69
|
+
|
|
71
70
|
def get_embedding_batch(embedding_model: Any, texts: List[str]) -> np.ndarray:
|
|
72
71
|
"""
|
|
73
|
-
|
|
72
|
+
为一批文本生成嵌入向量。
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
embedding_model:
|
|
77
|
-
texts:
|
|
74
|
+
参数:
|
|
75
|
+
embedding_model: 使用的嵌入模型
|
|
76
|
+
texts: 要嵌入的文本列表
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
np.ndarray:
|
|
78
|
+
返回:
|
|
79
|
+
np.ndarray: 堆叠的嵌入向量
|
|
81
80
|
"""
|
|
82
81
|
try:
|
|
83
82
|
all_vectors = []
|
|
@@ -90,41 +89,41 @@ def get_embedding_batch(embedding_model: Any, texts: List[str]) -> np.ndarray:
|
|
|
90
89
|
return np.zeros((0, embedding_model.get_sentence_embedding_dimension()), dtype=np.float32)
|
|
91
90
|
|
|
92
91
|
def split_text_into_chunks(text: str, max_length: int = 512) -> List[str]:
|
|
93
|
-
"""
|
|
92
|
+
"""将文本分割成带重叠窗口的块。
|
|
94
93
|
|
|
95
|
-
|
|
96
|
-
text:
|
|
97
|
-
max_length:
|
|
94
|
+
参数:
|
|
95
|
+
text: 要分割的输入文本
|
|
96
|
+
max_length: 每个块的最大长度
|
|
98
97
|
|
|
99
|
-
|
|
100
|
-
List[str]:
|
|
98
|
+
返回:
|
|
99
|
+
List[str]: 文本块列表
|
|
101
100
|
"""
|
|
102
101
|
chunks = []
|
|
103
102
|
start = 0
|
|
104
103
|
while start < len(text):
|
|
105
104
|
end = start + max_length
|
|
106
|
-
#
|
|
105
|
+
# 找到最近的句子边界
|
|
107
106
|
if end < len(text):
|
|
108
107
|
while end > start and text[end] not in {'.', '!', '?', '\n'}:
|
|
109
108
|
end -= 1
|
|
110
|
-
if end == start: #
|
|
109
|
+
if end == start: # 未找到标点,强制分割
|
|
111
110
|
end = start + max_length
|
|
112
111
|
chunk = text[start:end]
|
|
113
112
|
chunks.append(chunk)
|
|
114
|
-
#
|
|
113
|
+
# 重叠20%的窗口
|
|
115
114
|
start = end - int(max_length * 0.2)
|
|
116
115
|
return chunks
|
|
117
116
|
|
|
118
117
|
def get_embedding_with_chunks(embedding_model: Any, text: str) -> List[np.ndarray]:
|
|
119
118
|
"""
|
|
120
|
-
|
|
119
|
+
为文本块生成嵌入向量。
|
|
121
120
|
|
|
122
|
-
|
|
123
|
-
embedding_model:
|
|
124
|
-
text:
|
|
121
|
+
参数:
|
|
122
|
+
embedding_model: 使用的嵌入模型
|
|
123
|
+
text: 要处理的输入文本
|
|
125
124
|
|
|
126
|
-
|
|
127
|
-
List[np.ndarray]:
|
|
125
|
+
返回:
|
|
126
|
+
List[np.ndarray]: 每个块的嵌入向量列表
|
|
128
127
|
"""
|
|
129
128
|
chunks = split_text_into_chunks(text, 512)
|
|
130
129
|
if not chunks:
|
|
@@ -135,12 +134,13 @@ def get_embedding_with_chunks(embedding_model: Any, text: str) -> List[np.ndarra
|
|
|
135
134
|
vector = get_embedding(embedding_model, chunk)
|
|
136
135
|
vectors.append(vector)
|
|
137
136
|
return vectors
|
|
137
|
+
|
|
138
138
|
def load_tokenizer() -> AutoTokenizer:
|
|
139
139
|
"""
|
|
140
|
-
|
|
140
|
+
加载用于文本处理的分词器。
|
|
141
141
|
|
|
142
|
-
|
|
143
|
-
AutoTokenizer:
|
|
142
|
+
返回:
|
|
143
|
+
AutoTokenizer: 加载的分词器
|
|
144
144
|
"""
|
|
145
145
|
model_name = "gpt2"
|
|
146
146
|
cache_dir = os.path.expanduser("~/.cache/huggingface/hub")
|
|
@@ -159,12 +159,13 @@ def load_tokenizer() -> AutoTokenizer:
|
|
|
159
159
|
)
|
|
160
160
|
|
|
161
161
|
return tokenizer # type: ignore
|
|
162
|
+
|
|
162
163
|
def load_rerank_model() -> Tuple[AutoModelForSequenceClassification, AutoTokenizer]:
|
|
163
164
|
"""
|
|
164
|
-
|
|
165
|
+
加载重排序模型和分词器。
|
|
165
166
|
|
|
166
|
-
|
|
167
|
-
Tuple[AutoModelForSequenceClassification, AutoTokenizer]:
|
|
167
|
+
返回:
|
|
168
|
+
Tuple[AutoModelForSequenceClassification, AutoTokenizer]: 加载的模型和分词器
|
|
168
169
|
"""
|
|
169
170
|
model_name = "BAAI/bge-reranker-v2-m3"
|
|
170
171
|
cache_dir = os.path.expanduser("~/.cache/huggingface/hub")
|
|
@@ -198,4 +199,4 @@ def load_rerank_model() -> Tuple[AutoModelForSequenceClassification, AutoTokeniz
|
|
|
198
199
|
model = model.cuda()
|
|
199
200
|
model.eval()
|
|
200
201
|
|
|
201
|
-
return model, tokenizer # type: ignore
|
|
202
|
+
return model, tokenizer # type: ignore
|
jarvis/jarvis_utils/git_utils.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Git
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
2
|
+
Git工具模块
|
|
3
|
+
该模块提供了与Git仓库交互的工具。
|
|
4
|
+
包含以下功能:
|
|
5
|
+
- 查找Git仓库的根目录
|
|
6
|
+
- 检查是否有未提交的更改
|
|
7
|
+
- 获取两个哈希值之间的提交历史
|
|
8
|
+
- 获取最新提交的哈希值
|
|
9
|
+
- 从Git差异中提取修改的行范围
|
|
10
10
|
"""
|
|
11
11
|
import os
|
|
12
12
|
import re
|
|
@@ -14,42 +14,42 @@ import subprocess
|
|
|
14
14
|
from typing import List, Tuple, Dict
|
|
15
15
|
from jarvis.jarvis_utils.output import PrettyOutput, OutputType
|
|
16
16
|
def find_git_root(start_dir="."):
|
|
17
|
-
"""
|
|
17
|
+
"""切换到给定路径的Git根目录"""
|
|
18
18
|
os.chdir(start_dir)
|
|
19
19
|
git_root = os.popen("git rev-parse --show-toplevel").read().strip()
|
|
20
20
|
os.chdir(git_root)
|
|
21
21
|
return git_root
|
|
22
22
|
def has_uncommitted_changes():
|
|
23
|
-
"""
|
|
24
|
-
#
|
|
23
|
+
"""检查Git仓库中是否有未提交的更改"""
|
|
24
|
+
# 静默添加所有更改
|
|
25
25
|
subprocess.run(["git", "add", "."], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
26
26
|
|
|
27
|
-
#
|
|
27
|
+
# 检查工作目录更改
|
|
28
28
|
working_changes = subprocess.run(["git", "diff", "--exit-code"],
|
|
29
29
|
stdout=subprocess.DEVNULL,
|
|
30
30
|
stderr=subprocess.DEVNULL).returncode != 0
|
|
31
31
|
|
|
32
|
-
#
|
|
32
|
+
# 检查暂存区更改
|
|
33
33
|
staged_changes = subprocess.run(["git", "diff", "--cached", "--exit-code"],
|
|
34
34
|
stdout=subprocess.DEVNULL,
|
|
35
35
|
stderr=subprocess.DEVNULL).returncode != 0
|
|
36
36
|
|
|
37
|
-
#
|
|
37
|
+
# 静默重置更改
|
|
38
38
|
subprocess.run(["git", "reset"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
39
39
|
|
|
40
40
|
return working_changes or staged_changes
|
|
41
41
|
def get_commits_between(start_hash: str, end_hash: str) -> List[Tuple[str, str]]:
|
|
42
|
-
"""
|
|
42
|
+
"""获取两个提交哈希值之间的提交列表
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
start_hash:
|
|
46
|
-
end_hash:
|
|
44
|
+
参数:
|
|
45
|
+
start_hash: 起始提交哈希值(不包含)
|
|
46
|
+
end_hash: 结束提交哈希值(包含)
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
List[Tuple[str, str]]:
|
|
48
|
+
返回:
|
|
49
|
+
List[Tuple[str, str]]: (提交哈希值, 提交信息) 元组列表
|
|
50
50
|
"""
|
|
51
51
|
try:
|
|
52
|
-
#
|
|
52
|
+
# 使用git log和pretty格式获取哈希值和信息
|
|
53
53
|
result = subprocess.run(
|
|
54
54
|
['git', 'log', f'{start_hash}..{end_hash}', '--pretty=format:%H|%s'],
|
|
55
55
|
stdout=subprocess.PIPE,
|
|
@@ -71,10 +71,10 @@ def get_commits_between(start_hash: str, end_hash: str) -> List[Tuple[str, str]]
|
|
|
71
71
|
PrettyOutput.print(f"获取commit历史异常: {str(e)}", OutputType.ERROR)
|
|
72
72
|
return []
|
|
73
73
|
def get_latest_commit_hash() -> str:
|
|
74
|
-
"""
|
|
74
|
+
"""获取当前Git仓库的最新提交哈希值
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
str:
|
|
76
|
+
返回:
|
|
77
|
+
str: 提交哈希值,如果不在Git仓库或发生错误则返回空字符串
|
|
78
78
|
"""
|
|
79
79
|
try:
|
|
80
80
|
result = subprocess.run(
|
|
@@ -89,32 +89,32 @@ def get_latest_commit_hash() -> str:
|
|
|
89
89
|
except Exception:
|
|
90
90
|
return ""
|
|
91
91
|
def get_modified_line_ranges() -> Dict[str, Tuple[int, int]]:
|
|
92
|
-
"""
|
|
92
|
+
"""从Git差异中获取所有更改文件的修改行范围
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
返回:
|
|
95
|
+
字典,将文件路径映射到包含修改部分的(起始行, 结束行)范围元组。
|
|
96
|
+
行号从1开始。
|
|
97
97
|
"""
|
|
98
|
-
#
|
|
98
|
+
# 获取所有文件的Git差异
|
|
99
99
|
diff_output = os.popen("git show").read()
|
|
100
100
|
|
|
101
|
-
#
|
|
101
|
+
# 解析差异以获取修改的文件及其行范围
|
|
102
102
|
result = {}
|
|
103
103
|
current_file = None
|
|
104
104
|
|
|
105
105
|
for line in diff_output.splitlines():
|
|
106
|
-
#
|
|
106
|
+
# 匹配类似"+++ b/path/to/file"的行
|
|
107
107
|
file_match = re.match(r"^\+\+\+ b/(.*)", line)
|
|
108
108
|
if file_match:
|
|
109
109
|
current_file = file_match.group(1)
|
|
110
110
|
continue
|
|
111
111
|
|
|
112
|
-
#
|
|
112
|
+
# 匹配类似"@@ -100,5 +100,7 @@"的行,其中+部分显示新行
|
|
113
113
|
range_match = re.match(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@", line)
|
|
114
114
|
if range_match and current_file:
|
|
115
|
-
start_line = int(range_match.group(1)) #
|
|
115
|
+
start_line = int(range_match.group(1)) # 保持从1开始
|
|
116
116
|
line_count = int(range_match.group(2)) if range_match.group(2) else 1
|
|
117
117
|
end_line = start_line + line_count - 1
|
|
118
118
|
result[current_file] = (start_line, end_line)
|
|
119
119
|
|
|
120
|
-
return result
|
|
120
|
+
return result
|
jarvis/jarvis_utils/globals.py
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
2
|
+
全局变量和配置模块
|
|
3
|
+
该模块管理Jarvis系统的全局状态和配置。
|
|
4
|
+
包含:
|
|
5
|
+
- 全局代理管理
|
|
6
|
+
- 带有自定义主题的控制台配置
|
|
7
|
+
- 环境初始化
|
|
8
8
|
"""
|
|
9
9
|
from typing import Any, Set
|
|
10
10
|
import colorama
|
|
11
11
|
import os
|
|
12
12
|
from rich.console import Console
|
|
13
13
|
from rich.theme import Theme
|
|
14
|
-
#
|
|
14
|
+
# 初始化colorama以支持跨平台的彩色文本
|
|
15
15
|
colorama.init()
|
|
16
|
-
#
|
|
16
|
+
# 禁用tokenizers并行以避免多进程问题
|
|
17
17
|
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
|
18
|
-
#
|
|
18
|
+
# 全局代理管理
|
|
19
19
|
global_agents: Set[str] = set()
|
|
20
20
|
current_agent_name: str = ""
|
|
21
|
-
#
|
|
21
|
+
# 使用自定义主题配置rich控制台
|
|
22
22
|
custom_theme = Theme({
|
|
23
23
|
"INFO": "yellow",
|
|
24
24
|
"WARNING": "yellow",
|
|
@@ -36,13 +36,13 @@ custom_theme = Theme({
|
|
|
36
36
|
console = Console(theme=custom_theme)
|
|
37
37
|
def make_agent_name(agent_name: str) -> str:
|
|
38
38
|
"""
|
|
39
|
-
|
|
39
|
+
通过附加后缀生成唯一的代理名称(如果必要)。
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
agent_name:
|
|
41
|
+
参数:
|
|
42
|
+
agent_name: 基础代理名称
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
str:
|
|
44
|
+
返回:
|
|
45
|
+
str: 唯一的代理名称
|
|
46
46
|
"""
|
|
47
47
|
if agent_name in global_agents:
|
|
48
48
|
i = 1
|
|
@@ -52,31 +52,31 @@ def make_agent_name(agent_name: str) -> str:
|
|
|
52
52
|
return agent_name
|
|
53
53
|
def set_agent(agent_name: str, agent: Any) -> None:
|
|
54
54
|
"""
|
|
55
|
-
|
|
55
|
+
设置当前代理并将其添加到全局代理集合中。
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
agent_name:
|
|
59
|
-
agent:
|
|
57
|
+
参数:
|
|
58
|
+
agent_name: 代理名称
|
|
59
|
+
agent: 代理对象
|
|
60
60
|
"""
|
|
61
61
|
global_agents.add(agent_name)
|
|
62
62
|
global current_agent_name
|
|
63
63
|
current_agent_name = agent_name
|
|
64
64
|
def get_agent_list() -> str:
|
|
65
65
|
"""
|
|
66
|
-
|
|
66
|
+
获取表示当前代理状态的格式化字符串。
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
str:
|
|
68
|
+
返回:
|
|
69
|
+
str: 包含代理数量和当前代理名称的格式化字符串
|
|
70
70
|
"""
|
|
71
71
|
return "[" + str(len(global_agents)) + "]" + current_agent_name if global_agents else ""
|
|
72
72
|
def delete_agent(agent_name: str) -> None:
|
|
73
73
|
"""
|
|
74
|
-
|
|
74
|
+
从全局代理集合中删除一个代理。
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
agent_name:
|
|
76
|
+
参数:
|
|
77
|
+
agent_name: 要删除的代理名称
|
|
78
78
|
"""
|
|
79
79
|
if agent_name in global_agents:
|
|
80
80
|
global_agents.remove(agent_name)
|
|
81
81
|
global current_agent_name
|
|
82
|
-
current_agent_name = ""
|
|
82
|
+
current_agent_name = ""
|