jarvis-ai-assistant 0.1.208__py3-none-any.whl → 0.1.210__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 +9 -59
- jarvis/jarvis_agent/edit_file_handler.py +1 -1
- jarvis/jarvis_code_agent/code_agent.py +55 -8
- jarvis/jarvis_code_agent/lint.py +1 -1
- jarvis/jarvis_data/config_schema.json +0 -25
- jarvis/jarvis_git_utils/git_commiter.py +2 -2
- jarvis/jarvis_platform/kimi.py +20 -11
- jarvis/jarvis_platform/tongyi.py +84 -74
- jarvis/jarvis_platform/yuanbao.py +60 -54
- jarvis/jarvis_tools/ask_user.py +0 -1
- jarvis/jarvis_tools/file_analyzer.py +0 -3
- jarvis/jarvis_utils/config.py +4 -49
- jarvis/jarvis_utils/embedding.py +6 -51
- jarvis/jarvis_utils/git_utils.py +74 -11
- jarvis/jarvis_utils/http.py +169 -0
- jarvis/jarvis_utils/utils.py +186 -63
- {jarvis_ai_assistant-0.1.208.dist-info → jarvis_ai_assistant-0.1.210.dist-info}/METADATA +5 -10
- {jarvis_ai_assistant-0.1.208.dist-info → jarvis_ai_assistant-0.1.210.dist-info}/RECORD +23 -24
- {jarvis_ai_assistant-0.1.208.dist-info → jarvis_ai_assistant-0.1.210.dist-info}/entry_points.txt +1 -0
- jarvis/jarvis_data/huggingface.tar.gz +0 -0
- jarvis/jarvis_utils/jarvis_history.py +0 -98
- {jarvis_ai_assistant-0.1.208.dist-info → jarvis_ai_assistant-0.1.210.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.208.dist-info → jarvis_ai_assistant-0.1.210.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.208.dist-info → jarvis_ai_assistant-0.1.210.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
jarvis/jarvis_agent/__init__.py
CHANGED
@@ -16,13 +16,9 @@ from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
16
16
|
|
17
17
|
# jarvis_utils 相关
|
18
18
|
from jarvis.jarvis_utils.config import (
|
19
|
-
get_data_dir,
|
20
19
|
get_max_token_count,
|
21
|
-
get_max_tool_call_count,
|
22
|
-
is_auto_complete,
|
23
20
|
is_execute_tool_confirm,
|
24
21
|
is_use_analysis,
|
25
|
-
get_history_count,
|
26
22
|
is_use_methodology,
|
27
23
|
)
|
28
24
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
@@ -34,7 +30,6 @@ from jarvis.jarvis_utils.globals import (
|
|
34
30
|
set_interrupt,
|
35
31
|
)
|
36
32
|
from jarvis.jarvis_utils.input import get_multiline_input
|
37
|
-
from jarvis.jarvis_utils.jarvis_history import JarvisHistory
|
38
33
|
from jarvis.jarvis_utils.methodology import load_methodology, upload_methodology
|
39
34
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
40
35
|
from jarvis.jarvis_utils.tag import ct, ot
|
@@ -147,7 +142,7 @@ class Agent:
|
|
147
142
|
self.prompt = ""
|
148
143
|
|
149
144
|
def __del__(self):
|
150
|
-
|
145
|
+
# 只有在记录启动时才停止记录
|
151
146
|
delete_agent(self.name)
|
152
147
|
|
153
148
|
def __init__(
|
@@ -158,7 +153,7 @@ class Agent:
|
|
158
153
|
platform: Union[Optional[BasePlatform], Optional[str]] = None,
|
159
154
|
model_name: Optional[str] = None,
|
160
155
|
summary_prompt: Optional[str] = None,
|
161
|
-
auto_complete:
|
156
|
+
auto_complete: bool = False,
|
162
157
|
output_handler: List[OutputHandlerProtocol] = [],
|
163
158
|
use_tools: List[str] = [],
|
164
159
|
input_handler: Optional[List[Callable[[str, Any], Tuple[str, bool]]]] = None,
|
@@ -168,7 +163,6 @@ class Agent:
|
|
168
163
|
use_methodology: Optional[bool] = None,
|
169
164
|
use_analysis: Optional[bool] = None,
|
170
165
|
files: List[str] = [],
|
171
|
-
history_count: Optional[int] = None,
|
172
166
|
):
|
173
167
|
self.files = files
|
174
168
|
"""初始化Jarvis Agent实例
|
@@ -243,18 +237,8 @@ class Agent:
|
|
243
237
|
# Load configuration from environment variables
|
244
238
|
self.addon_prompt = ""
|
245
239
|
|
246
|
-
self.tool_call_count = 0
|
247
|
-
self.max_tool_call_count = get_max_tool_call_count()
|
248
240
|
self.after_tool_call_cb: Optional[Callable[[Agent], None]] = None
|
249
241
|
|
250
|
-
self.history = JarvisHistory()
|
251
|
-
self.history_dir = str(Path(get_data_dir()) / "history")
|
252
|
-
self.history.start_record(self.history_dir)
|
253
|
-
|
254
|
-
self.history_count = (
|
255
|
-
history_count if history_count is not None else get_history_count()
|
256
|
-
)
|
257
|
-
|
258
242
|
self.execute_tool_confirm = (
|
259
243
|
execute_tool_confirm
|
260
244
|
if execute_tool_confirm is not None
|
@@ -283,9 +267,7 @@ class Agent:
|
|
283
267
|
)
|
284
268
|
|
285
269
|
self.max_token_count = get_max_token_count()
|
286
|
-
self.auto_complete =
|
287
|
-
auto_complete if auto_complete is not None else is_auto_complete()
|
288
|
-
)
|
270
|
+
self.auto_complete = auto_complete
|
289
271
|
welcome_message = f"{name} 初始化完成 - 使用 {self.model.name()} 模型"
|
290
272
|
|
291
273
|
PrettyOutput.print(welcome_message, OutputType.SYSTEM)
|
@@ -416,10 +398,10 @@ class Agent:
|
|
416
398
|
if self.conversation_length > self.max_token_count:
|
417
399
|
message = self._summarize_and_clear_history() + "\n\n" + message
|
418
400
|
self.conversation_length += get_context_token_count(message)
|
419
|
-
|
401
|
+
|
420
402
|
response = self.model.chat_until_success(message) # type: ignore
|
421
403
|
self.conversation_length += get_context_token_count(response)
|
422
|
-
|
404
|
+
|
423
405
|
return response
|
424
406
|
|
425
407
|
def generate_summary(self) -> str:
|
@@ -491,7 +473,6 @@ class Agent:
|
|
491
473
|
|
492
474
|
tmp_file = tempfile.NamedTemporaryFile(delete=False)
|
493
475
|
tmp_file_name = tmp_file.name
|
494
|
-
self.history.save_history(tmp_file_name)
|
495
476
|
self.clear_history() # type: ignore
|
496
477
|
|
497
478
|
if need_summary:
|
@@ -547,29 +528,17 @@ class Agent:
|
|
547
528
|
)
|
548
529
|
if len(tool_list) == 0:
|
549
530
|
return False, ""
|
550
|
-
|
551
|
-
self.max_tool_call_count > 0
|
552
|
-
and self.tool_call_count >= self.max_tool_call_count
|
553
|
-
):
|
554
|
-
if user_confirm(f"工具调用次数超过限制,是否继续执行?", True):
|
555
|
-
self.reset_tool_call_count()
|
556
|
-
else:
|
557
|
-
return False, ""
|
558
|
-
if self.execute_tool_confirm:
|
559
|
-
self.reset_tool_call_count()
|
531
|
+
|
560
532
|
if not self.execute_tool_confirm or user_confirm(
|
561
533
|
f"需要执行{tool_list[0].name()}确认执行?", True
|
562
534
|
):
|
563
535
|
print(f"🔧 正在执行{tool_list[0].name()}...")
|
564
536
|
result = tool_list[0].handle(response, self)
|
565
537
|
print(f"✅ {tool_list[0].name()}执行完成")
|
566
|
-
|
538
|
+
|
567
539
|
return result
|
568
540
|
return False, ""
|
569
541
|
|
570
|
-
def reset_tool_call_count(self):
|
571
|
-
self.tool_call_count = 0
|
572
|
-
|
573
542
|
def _complete_task(self) -> str:
|
574
543
|
"""完成任务并生成总结(如果需要)
|
575
544
|
|
@@ -804,9 +773,8 @@ arguments:
|
|
804
773
|
set_agent(self.name, self)
|
805
774
|
|
806
775
|
while True:
|
807
|
-
history_md = ""
|
808
776
|
if self.first:
|
809
|
-
|
777
|
+
self._first_run()
|
810
778
|
try:
|
811
779
|
current_response = self._call_model(self.prompt, True)
|
812
780
|
self.prompt = ""
|
@@ -844,8 +812,6 @@ arguments:
|
|
844
812
|
if self.auto_complete and ot("!!!COMPLETE!!!") in current_response:
|
845
813
|
return self._complete_task()
|
846
814
|
|
847
|
-
self.reset_tool_call_count()
|
848
|
-
|
849
815
|
# 获取用户输入
|
850
816
|
user_input = self.multiline_inputer(
|
851
817
|
f"{self.name}: 请输入,或输入空行来结束当前任务:"
|
@@ -859,8 +825,6 @@ arguments:
|
|
859
825
|
return self._complete_task()
|
860
826
|
|
861
827
|
except Exception as e:
|
862
|
-
if history_md:
|
863
|
-
os.remove(history_md)
|
864
828
|
PrettyOutput.print(f"任务失败: {str(e)}", OutputType.ERROR)
|
865
829
|
return f"Task failed: {str(e)}"
|
866
830
|
|
@@ -869,20 +833,7 @@ arguments:
|
|
869
833
|
return f"Task failed: {str(e)}"
|
870
834
|
|
871
835
|
def _first_run(self):
|
872
|
-
|
873
|
-
if self.history_count > 0 and self.model and self.model.support_upload_files():
|
874
|
-
import tempfile
|
875
|
-
|
876
|
-
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
877
|
-
history_md = str(
|
878
|
-
Path(tempfile.gettempdir()) / f"{self.name}_history_{timestamp}.md"
|
879
|
-
)
|
880
|
-
self.history.export_history_to_markdown(
|
881
|
-
self.history_dir, history_md, max_files=self.history_count
|
882
|
-
)
|
883
|
-
self.files.append(history_md)
|
884
|
-
|
885
|
-
# 如果有上传文件,先上传文件
|
836
|
+
# 如果有上传文件,先上传文件
|
886
837
|
if self.model and self.model.support_upload_files():
|
887
838
|
if self.use_methodology:
|
888
839
|
if not upload_methodology(self.model, other_files=self.files):
|
@@ -917,7 +868,6 @@ arguments:
|
|
917
868
|
self.prompt = f"{self.prompt}\n\n以下是历史类似问题的执行经验,可参考:\n{load_methodology(msg, self.get_tool_registry())}"
|
918
869
|
|
919
870
|
self.first = False
|
920
|
-
return history_md
|
921
871
|
|
922
872
|
def clear_history(self):
|
923
873
|
"""清空对话历史但保留系统提示
|
@@ -21,7 +21,7 @@ from jarvis.jarvis_tools.registry import ToolRegistry
|
|
21
21
|
from jarvis.jarvis_utils.config import is_confirm_before_apply_patch
|
22
22
|
from jarvis.jarvis_utils.git_utils import (
|
23
23
|
confirm_add_new_files,
|
24
|
-
|
24
|
+
find_git_root_and_cd,
|
25
25
|
get_commits_between,
|
26
26
|
get_diff,
|
27
27
|
get_diff_file_list,
|
@@ -130,22 +130,69 @@ class CodeAgent:
|
|
130
130
|
platform=platform_instance,
|
131
131
|
input_handler=[shell_input_handler, builtin_input_handler],
|
132
132
|
need_summary=need_summary,
|
133
|
+
use_methodology=False, # 禁用方法论
|
134
|
+
use_analysis=False # 禁用分析
|
133
135
|
)
|
134
136
|
|
135
137
|
self.agent.set_after_tool_call_cb(self.after_tool_call_cb)
|
136
138
|
|
137
|
-
def
|
138
|
-
"""
|
139
|
-
|
140
|
-
|
139
|
+
def _find_git_root(self) -> str:
|
140
|
+
"""查找并切换到git根目录
|
141
|
+
|
142
|
+
返回:
|
143
|
+
str: git根目录路径
|
141
144
|
"""
|
142
|
-
print("
|
145
|
+
print("🔍 正在查找git根目录...")
|
143
146
|
curr_dir = os.getcwd()
|
144
|
-
git_dir =
|
147
|
+
git_dir = find_git_root_and_cd(curr_dir)
|
145
148
|
self.root_dir = git_dir
|
149
|
+
print(f"✅ 已找到git根目录: {git_dir}")
|
150
|
+
return git_dir
|
151
|
+
|
152
|
+
def _update_gitignore(self, git_dir: str) -> None:
|
153
|
+
"""检查并更新.gitignore文件,确保忽略.jarvis目录
|
154
|
+
|
155
|
+
参数:
|
156
|
+
git_dir: git根目录路径
|
157
|
+
"""
|
158
|
+
print("📝 正在检查.gitignore文件...")
|
159
|
+
gitignore_path = os.path.join(git_dir, ".gitignore")
|
160
|
+
jarvis_ignore = ".jarvis"
|
161
|
+
|
162
|
+
if not os.path.exists(gitignore_path):
|
163
|
+
with open(gitignore_path, "w") as f:
|
164
|
+
f.write(f"{jarvis_ignore}\n")
|
165
|
+
print(f"✅ 已创建.gitignore文件并添加'{jarvis_ignore}'")
|
166
|
+
else:
|
167
|
+
with open(gitignore_path, "r+") as f:
|
168
|
+
content = f.read()
|
169
|
+
if jarvis_ignore not in content.splitlines():
|
170
|
+
f.write(f"\n{jarvis_ignore}\n")
|
171
|
+
print(f"✅ 已更新.gitignore文件,添加'{jarvis_ignore}'")
|
172
|
+
else:
|
173
|
+
print("ℹ️ .jarvis已在.gitignore中")
|
174
|
+
|
175
|
+
def _handle_git_changes(self) -> None:
|
176
|
+
"""处理git仓库中的未提交修改"""
|
177
|
+
print("🔄 正在检查未提交的修改...")
|
146
178
|
if has_uncommitted_changes():
|
179
|
+
print("⏳ 发现未提交修改,正在处理...")
|
147
180
|
git_commiter = GitCommitTool()
|
148
181
|
git_commiter.execute({})
|
182
|
+
print("✅ 未提交修改已处理完成")
|
183
|
+
else:
|
184
|
+
print("✅ 没有未提交的修改")
|
185
|
+
|
186
|
+
def _init_env(self) -> None:
|
187
|
+
"""初始化环境,组合以下功能:
|
188
|
+
1. 查找git根目录
|
189
|
+
2. 检查并更新.gitignore文件
|
190
|
+
3. 处理未提交的修改
|
191
|
+
"""
|
192
|
+
print("🚀 正在初始化环境...")
|
193
|
+
git_dir = self._find_git_root()
|
194
|
+
self._update_gitignore(git_dir)
|
195
|
+
self._handle_git_changes()
|
149
196
|
print("✅ 环境初始化完成")
|
150
197
|
|
151
198
|
def _handle_uncommitted_changes(self) -> None:
|
@@ -376,7 +423,7 @@ def main() -> None:
|
|
376
423
|
args = parser.parse_args()
|
377
424
|
|
378
425
|
curr_dir = os.getcwd()
|
379
|
-
git_dir =
|
426
|
+
git_dir = find_git_root_and_cd(curr_dir)
|
380
427
|
PrettyOutput.print(f"当前目录: {git_dir}", OutputType.INFO)
|
381
428
|
|
382
429
|
try:
|
jarvis/jarvis_code_agent/lint.py
CHANGED
@@ -121,16 +121,6 @@
|
|
121
121
|
"description": "模型能处理的最大输入token数量",
|
122
122
|
"default": 32000
|
123
123
|
},
|
124
|
-
"JARVIS_AUTO_COMPLETE": {
|
125
|
-
"type": "boolean",
|
126
|
-
"description": "是否启用自动补全功能",
|
127
|
-
"default": false
|
128
|
-
},
|
129
|
-
"SHELL": {
|
130
|
-
"type": "string",
|
131
|
-
"description": "系统shell名称(如: bash, zsh)",
|
132
|
-
"default": "/bin/bash"
|
133
|
-
},
|
134
124
|
"JARVIS_PLATFORM": {
|
135
125
|
"type": "string",
|
136
126
|
"description": "常规操作平台名称",
|
@@ -161,21 +151,11 @@
|
|
161
151
|
"description": "应用补丁前是否需要确认",
|
162
152
|
"default": false
|
163
153
|
},
|
164
|
-
"JARVIS_MAX_TOOL_CALL_COUNT": {
|
165
|
-
"type": "number",
|
166
|
-
"description": "最大连续工具调用次数",
|
167
|
-
"default": 20
|
168
|
-
},
|
169
154
|
"JARVIS_DATA_PATH": {
|
170
155
|
"type": "string",
|
171
156
|
"description": "Jarvis数据存储目录路径",
|
172
157
|
"default": "~/.jarvis"
|
173
158
|
},
|
174
|
-
"JARVIS_AUTO_UPDATE": {
|
175
|
-
"type": "boolean",
|
176
|
-
"description": "是否自动更新git仓库",
|
177
|
-
"default": true
|
178
|
-
},
|
179
159
|
"JARVIS_MAX_BIG_CONTENT_SIZE": {
|
180
160
|
"type": "number",
|
181
161
|
"description": "最大大内容尺寸",
|
@@ -201,11 +181,6 @@
|
|
201
181
|
"description": "是否打印提示",
|
202
182
|
"default": false
|
203
183
|
},
|
204
|
-
"JARVIS_USE_HISTORY_COUNT": {
|
205
|
-
"type": "number",
|
206
|
-
"description": "使用的历史记录数量",
|
207
|
-
"default": 0
|
208
|
-
},
|
209
184
|
"JARVIS_REPLACE_MAP": {
|
210
185
|
"type": "object",
|
211
186
|
"description": "自定义替换映射表配置",
|
@@ -13,7 +13,7 @@ from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
13
13
|
from jarvis.jarvis_utils.config import get_git_commit_prompt
|
14
14
|
from jarvis.jarvis_utils.git_utils import (
|
15
15
|
confirm_add_new_files,
|
16
|
-
|
16
|
+
find_git_root_and_cd,
|
17
17
|
has_uncommitted_changes,
|
18
18
|
)
|
19
19
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
@@ -71,7 +71,7 @@ class GitCommitTool:
|
|
71
71
|
"""Prepare git environment by changing directory and checking for changes"""
|
72
72
|
original_dir = os.getcwd()
|
73
73
|
os.chdir(root_dir)
|
74
|
-
|
74
|
+
find_git_root_and_cd()
|
75
75
|
if not has_uncommitted_changes():
|
76
76
|
PrettyOutput.print("没有未提交的更改", OutputType.SUCCESS)
|
77
77
|
return None
|
jarvis/jarvis_platform/kimi.py
CHANGED
@@ -7,9 +7,8 @@ import os
|
|
7
7
|
import time
|
8
8
|
from typing import Dict, Generator, List, Tuple
|
9
9
|
|
10
|
-
import requests # type: ignore
|
11
|
-
|
12
10
|
from jarvis.jarvis_platform.base import BasePlatform
|
11
|
+
from jarvis.jarvis_utils import http
|
13
12
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
14
13
|
from jarvis.jarvis_utils.utils import while_success
|
15
14
|
|
@@ -67,7 +66,7 @@ class KimiModel(BasePlatform):
|
|
67
66
|
}
|
68
67
|
try:
|
69
68
|
response = while_success(
|
70
|
-
lambda:
|
69
|
+
lambda: http.post(url, headers=headers, data=payload),
|
71
70
|
sleep_time=5,
|
72
71
|
)
|
73
72
|
if response.status_code != 200:
|
@@ -95,7 +94,7 @@ class KimiModel(BasePlatform):
|
|
95
94
|
}
|
96
95
|
|
97
96
|
response = while_success(
|
98
|
-
lambda:
|
97
|
+
lambda: http.post(url, headers=headers, data=payload), sleep_time=5
|
99
98
|
)
|
100
99
|
return response.json()
|
101
100
|
|
@@ -109,7 +108,7 @@ class KimiModel(BasePlatform):
|
|
109
108
|
with open(file_path, "rb") as f:
|
110
109
|
content = f.read()
|
111
110
|
response = while_success(
|
112
|
-
lambda:
|
111
|
+
lambda: http.put(presigned_url, data=content), sleep_time=5
|
113
112
|
)
|
114
113
|
return response.status_code == 200
|
115
114
|
except Exception as e:
|
@@ -136,7 +135,7 @@ class KimiModel(BasePlatform):
|
|
136
135
|
}
|
137
136
|
|
138
137
|
response = while_success(
|
139
|
-
lambda:
|
138
|
+
lambda: http.post(url, headers=headers, data=payload), sleep_time=5
|
140
139
|
)
|
141
140
|
return response.json()
|
142
141
|
|
@@ -154,7 +153,7 @@ class KimiModel(BasePlatform):
|
|
154
153
|
while retry_count < max_retries:
|
155
154
|
payload = json.dumps({"ids": [file_id]}, ensure_ascii=False)
|
156
155
|
response = while_success(
|
157
|
-
lambda:
|
156
|
+
lambda: http.post(url, headers=headers, data=payload, stream=True),
|
158
157
|
sleep_time=5,
|
159
158
|
)
|
160
159
|
|
@@ -162,7 +161,12 @@ class KimiModel(BasePlatform):
|
|
162
161
|
if not line:
|
163
162
|
continue
|
164
163
|
|
165
|
-
|
164
|
+
# httpx 返回字符串,requests 返回字节,需要兼容处理
|
165
|
+
if isinstance(line, bytes):
|
166
|
+
line = line.decode("utf-8")
|
167
|
+
else:
|
168
|
+
line = str(line)
|
169
|
+
|
166
170
|
if not line.startswith("data: "):
|
167
171
|
continue
|
168
172
|
|
@@ -281,7 +285,7 @@ class KimiModel(BasePlatform):
|
|
281
285
|
|
282
286
|
try:
|
283
287
|
response = while_success(
|
284
|
-
lambda:
|
288
|
+
lambda: http.post(url, headers=headers, json=payload, stream=True),
|
285
289
|
sleep_time=5,
|
286
290
|
)
|
287
291
|
# 如果禁止输出,则静默处理
|
@@ -289,7 +293,12 @@ class KimiModel(BasePlatform):
|
|
289
293
|
if not line:
|
290
294
|
continue
|
291
295
|
|
292
|
-
|
296
|
+
# httpx 返回字符串,requests 返回字节,需要兼容处理
|
297
|
+
if isinstance(line, bytes):
|
298
|
+
line = line.decode("utf-8")
|
299
|
+
else:
|
300
|
+
line = str(line)
|
301
|
+
|
293
302
|
if not line.startswith("data: "):
|
294
303
|
continue
|
295
304
|
|
@@ -323,7 +332,7 @@ class KimiModel(BasePlatform):
|
|
323
332
|
|
324
333
|
try:
|
325
334
|
response = while_success(
|
326
|
-
lambda:
|
335
|
+
lambda: http.delete(url, headers=headers), sleep_time=5
|
327
336
|
)
|
328
337
|
if response.status_code == 200:
|
329
338
|
self.chat_id = ""
|