jarvis-ai-assistant 0.3.31__py3-none-any.whl → 0.3.33__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/agent_manager.py +6 -1
- jarvis/jarvis_agent/edit_file_handler.py +30 -12
- jarvis/jarvis_agent/file_context_handler.py +69 -0
- jarvis/jarvis_agent/jarvis.py +154 -29
- jarvis/jarvis_agent/run_loop.py +9 -0
- jarvis/jarvis_code_agent/code_agent.py +6 -1
- jarvis/jarvis_data/config_schema.json +5 -0
- jarvis/jarvis_multi_agent/__init__.py +21 -0
- jarvis/jarvis_platform/base.py +57 -0
- jarvis/jarvis_platform/openai.py +26 -1
- jarvis/jarvis_tools/edit_file.py +7 -7
- jarvis/jarvis_tools/read_webpage.py +4 -2
- jarvis/jarvis_tools/search_web.py +14 -10
- jarvis/jarvis_utils/config.py +10 -0
- jarvis/jarvis_utils/git_utils.py +1 -1
- jarvis/jarvis_utils/input.py +1 -1
- jarvis/jarvis_utils/utils.py +2 -2
- {jarvis_ai_assistant-0.3.31.dist-info → jarvis_ai_assistant-0.3.33.dist-info}/METADATA +1 -1
- {jarvis_ai_assistant-0.3.31.dist-info → jarvis_ai_assistant-0.3.33.dist-info}/RECORD +24 -23
- {jarvis_ai_assistant-0.3.31.dist-info → jarvis_ai_assistant-0.3.33.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.3.31.dist-info → jarvis_ai_assistant-0.3.33.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.3.31.dist-info → jarvis_ai_assistant-0.3.33.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.31.dist-info → jarvis_ai_assistant-0.3.33.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
@@ -12,6 +12,7 @@ from jarvis.jarvis_agent import (
|
|
12
12
|
origin_agent_system_prompt,
|
13
13
|
)
|
14
14
|
from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
|
15
|
+
from jarvis.jarvis_agent.file_context_handler import file_context_handler
|
15
16
|
from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
|
16
17
|
from jarvis.jarvis_agent.task_manager import TaskManager
|
17
18
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
@@ -46,7 +47,11 @@ class AgentManager:
|
|
46
47
|
self.agent = Agent(
|
47
48
|
system_prompt=origin_agent_system_prompt,
|
48
49
|
model_group=self.model_group,
|
49
|
-
input_handler=[
|
50
|
+
input_handler=[
|
51
|
+
shell_input_handler,
|
52
|
+
file_context_handler,
|
53
|
+
builtin_input_handler,
|
54
|
+
],
|
50
55
|
output_handler=[ToolRegistry()], # type: ignore
|
51
56
|
need_summary=False,
|
52
57
|
use_methodology=self.use_methodology,
|
@@ -166,7 +166,7 @@ class EditFileHandler(OutputHandler):
|
|
166
166
|
- {supported_formats}
|
167
167
|
- {ot("RANGE")}start-end{ct("RANGE")} 仅用于区间替换模式(SEARCH_START/SEARCH_END),表示只在指定行号范围内进行匹配与替换(1-based,闭区间);省略则在整个文件范围内处理
|
168
168
|
- 单点替换要求 SEARCH 在有效范围内唯一匹配(仅替换第一个匹配)
|
169
|
-
-
|
169
|
+
- 区间替换会从包含 {ot("SEARCH_START")} 的行首开始,到包含 {ot("SEARCH_END")} 的行尾结束,替换整个区域
|
170
170
|
否则编辑将失败。"""
|
171
171
|
|
172
172
|
def name(self) -> str:
|
@@ -468,24 +468,42 @@ class EditFileHandler(OutputHandler):
|
|
468
468
|
error_msg = "未找到SEARCH_START"
|
469
469
|
failed_patches.append({"patch": patch, "error": error_msg})
|
470
470
|
else:
|
471
|
-
|
471
|
+
# 从 search_start 之后开始查找 search_end
|
472
|
+
end_idx = base_content.find(search_end, start_idx + len(search_start))
|
472
473
|
if end_idx == -1:
|
473
474
|
error_msg = "在SEARCH_START之后未找到SEARCH_END"
|
474
475
|
failed_patches.append({"patch": patch, "error": error_msg})
|
475
476
|
else:
|
476
|
-
#
|
477
|
-
#
|
478
|
-
|
479
|
-
|
477
|
+
# 将替换范围扩展到整行
|
478
|
+
# 找到 start_idx 所在行的行首
|
479
|
+
line_start_idx = base_content.rfind("\n", 0, start_idx) + 1
|
480
|
+
|
481
|
+
# 找到 end_idx 所在行的行尾
|
482
|
+
match_end_pos = end_idx + len(search_end)
|
483
|
+
line_end_idx = base_content.find("\n", match_end_pos)
|
484
|
+
|
485
|
+
if line_end_idx == -1:
|
486
|
+
# 如果没有找到换行符,说明是最后一行
|
487
|
+
end_of_range = len(base_content)
|
488
|
+
else:
|
489
|
+
# 包含换行符
|
490
|
+
end_of_range = line_end_idx + 1
|
491
|
+
|
492
|
+
final_replace_text = replace_text
|
493
|
+
original_slice = base_content[line_start_idx:end_of_range]
|
494
|
+
|
495
|
+
# 如果原始片段以换行符结尾,且替换内容不为空且不以换行符结尾,
|
496
|
+
# 则为替换内容添加换行符以保持格式
|
480
497
|
if (
|
481
|
-
|
482
|
-
and
|
483
|
-
and
|
498
|
+
final_replace_text
|
499
|
+
and original_slice.endswith("\n")
|
500
|
+
and not final_replace_text.endswith("\n")
|
484
501
|
):
|
485
|
-
|
502
|
+
final_replace_text += "\n"
|
503
|
+
|
486
504
|
base_content = (
|
487
|
-
base_content[:
|
488
|
-
+
|
505
|
+
base_content[:line_start_idx]
|
506
|
+
+ final_replace_text
|
489
507
|
+ base_content[end_of_range:]
|
490
508
|
)
|
491
509
|
found = True
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
import re
|
3
|
+
import os
|
4
|
+
from typing import Any, Tuple
|
5
|
+
|
6
|
+
from jarvis.jarvis_tools.read_code import ReadCodeTool
|
7
|
+
|
8
|
+
|
9
|
+
def is_text_file(filepath: str) -> bool:
|
10
|
+
"""
|
11
|
+
Check if a file is a text file.
|
12
|
+
"""
|
13
|
+
try:
|
14
|
+
with open(filepath, "r", encoding="utf-8") as f:
|
15
|
+
f.read(1024) # Try to read a small chunk
|
16
|
+
return True
|
17
|
+
except (UnicodeDecodeError, IOError):
|
18
|
+
return False
|
19
|
+
|
20
|
+
|
21
|
+
def count_lines(filepath: str) -> int:
|
22
|
+
"""
|
23
|
+
Count the number of lines in a file.
|
24
|
+
"""
|
25
|
+
try:
|
26
|
+
with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
|
27
|
+
return sum(1 for _ in f)
|
28
|
+
except IOError:
|
29
|
+
return 0
|
30
|
+
|
31
|
+
|
32
|
+
def file_context_handler(user_input: str, agent_: Any) -> Tuple[str, bool]:
|
33
|
+
"""
|
34
|
+
Extracts file paths from the input, reads their content if they are valid text files
|
35
|
+
and appends the content to the input.
|
36
|
+
|
37
|
+
Args:
|
38
|
+
user_input: The user's input string.
|
39
|
+
agent_: The agent instance.
|
40
|
+
|
41
|
+
Returns:
|
42
|
+
A tuple containing the modified user input and a boolean indicating if
|
43
|
+
further processing should be skipped.
|
44
|
+
"""
|
45
|
+
# Regex to find paths in single quotes
|
46
|
+
file_paths = re.findall(r"'([^']+)'", user_input)
|
47
|
+
|
48
|
+
if not file_paths:
|
49
|
+
return user_input, False
|
50
|
+
|
51
|
+
added_context = ""
|
52
|
+
read_code_tool = ReadCodeTool()
|
53
|
+
|
54
|
+
for path in file_paths:
|
55
|
+
if os.path.isfile(path) and is_text_file(path):
|
56
|
+
line_count = count_lines(path)
|
57
|
+
if line_count > 0:
|
58
|
+
# Use ReadCodeTool to get formatted content
|
59
|
+
result = read_code_tool._handle_single_file(path)
|
60
|
+
if result["success"]:
|
61
|
+
# Remove the file path from the original input to avoid redundancy
|
62
|
+
user_input = user_input.replace(f"'{path}'", "")
|
63
|
+
# Append the full, formatted output from the tool, which includes headers and line numbers
|
64
|
+
added_context += "\n" + result["stdout"]
|
65
|
+
|
66
|
+
if added_context:
|
67
|
+
user_input = user_input.strip() + added_context
|
68
|
+
|
69
|
+
return user_input, False
|
jarvis/jarvis_agent/jarvis.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
"""Jarvis AI 助手主入口模块"""
|
3
3
|
from typing import Optional, List
|
4
|
+
import shutil
|
5
|
+
from datetime import datetime
|
4
6
|
|
5
7
|
import typer
|
6
8
|
|
@@ -16,6 +18,7 @@ from jarvis.jarvis_utils.config import (
|
|
16
18
|
get_agent_definition_dirs,
|
17
19
|
get_multi_agent_dirs,
|
18
20
|
get_roles_dirs,
|
21
|
+
get_data_dir,
|
19
22
|
)
|
20
23
|
import jarvis.jarvis_utils.utils as jutils
|
21
24
|
from jarvis.jarvis_utils.input import user_confirm, get_single_line_input
|
@@ -184,6 +187,91 @@ def handle_interactive_config_option(
|
|
184
187
|
return True
|
185
188
|
|
186
189
|
|
190
|
+
def handle_backup_option(backup: bool) -> bool:
|
191
|
+
"""处理数据备份选项,返回是否已处理并需提前结束。"""
|
192
|
+
if not backup:
|
193
|
+
return False
|
194
|
+
|
195
|
+
init_env("", config_file=None)
|
196
|
+
data_dir = Path(get_data_dir())
|
197
|
+
if not data_dir.is_dir():
|
198
|
+
PrettyOutput.print(f"数据目录不存在: {data_dir}", OutputType.ERROR)
|
199
|
+
return True
|
200
|
+
|
201
|
+
backup_dir = Path(os.path.expanduser("~/jarvis_backups"))
|
202
|
+
backup_dir.mkdir(exist_ok=True)
|
203
|
+
|
204
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
205
|
+
backup_file_base = backup_dir / f"jarvis_data_{timestamp}"
|
206
|
+
|
207
|
+
try:
|
208
|
+
archive_path = shutil.make_archive(
|
209
|
+
str(backup_file_base), "zip", root_dir=str(data_dir)
|
210
|
+
)
|
211
|
+
PrettyOutput.print(f"数据已成功备份到: {archive_path}", OutputType.SUCCESS)
|
212
|
+
except Exception as e:
|
213
|
+
PrettyOutput.print(f"数据备份失败: {e}", OutputType.ERROR)
|
214
|
+
|
215
|
+
return True
|
216
|
+
|
217
|
+
|
218
|
+
def handle_restore_option(restore_path: Optional[str], config_file: Optional[str]) -> bool:
|
219
|
+
"""处理数据恢复选项,返回是否已处理并需提前结束。"""
|
220
|
+
if not restore_path:
|
221
|
+
return False
|
222
|
+
|
223
|
+
restore_file = Path(os.path.expanduser(os.path.expandvars(restore_path)))
|
224
|
+
# 兼容 ~ 与环境变量,避免用户输入未展开路径导致找不到文件
|
225
|
+
if not restore_file.is_file():
|
226
|
+
PrettyOutput.print(f"指定的恢复文件不存在: {restore_file}", OutputType.ERROR)
|
227
|
+
return True
|
228
|
+
|
229
|
+
# 在恢复数据时不要触发完整环境初始化,避免引导流程或网络请求
|
230
|
+
# 优先从配置文件解析 JARVIS_DATA_PATH,否则回退到默认数据目录
|
231
|
+
data_dir_str: Optional[str] = None
|
232
|
+
try:
|
233
|
+
if config_file:
|
234
|
+
cfg_path = Path(os.path.expanduser(os.path.expandvars(config_file)))
|
235
|
+
if cfg_path.is_file():
|
236
|
+
with open(cfg_path, "r", encoding="utf-8", errors="ignore") as cf:
|
237
|
+
cfg_data = yaml.safe_load(cf) or {}
|
238
|
+
if isinstance(cfg_data, dict):
|
239
|
+
val = cfg_data.get("JARVIS_DATA_PATH")
|
240
|
+
if isinstance(val, str) and val.strip():
|
241
|
+
data_dir_str = val.strip()
|
242
|
+
except Exception:
|
243
|
+
data_dir_str = None
|
244
|
+
|
245
|
+
if not data_dir_str:
|
246
|
+
data_dir_str = get_data_dir()
|
247
|
+
|
248
|
+
data_dir = Path(os.path.expanduser(os.path.expandvars(str(data_dir_str))))
|
249
|
+
|
250
|
+
if data_dir.exists():
|
251
|
+
if not user_confirm(
|
252
|
+
f"数据目录 '{data_dir}' 已存在,恢复操作将覆盖它。是否继续?", default=False
|
253
|
+
):
|
254
|
+
PrettyOutput.print("恢复操作已取消。", OutputType.INFO)
|
255
|
+
return True
|
256
|
+
try:
|
257
|
+
shutil.rmtree(data_dir)
|
258
|
+
except Exception as e:
|
259
|
+
PrettyOutput.print(f"无法移除现有数据目录: {e}", OutputType.ERROR)
|
260
|
+
return True
|
261
|
+
|
262
|
+
try:
|
263
|
+
data_dir.mkdir(parents=True)
|
264
|
+
shutil.unpack_archive(str(restore_file), str(data_dir), "zip")
|
265
|
+
PrettyOutput.print(
|
266
|
+
f"数据已从 '{restore_path}' 成功恢复到 '{data_dir}'", OutputType.SUCCESS
|
267
|
+
)
|
268
|
+
|
269
|
+
except Exception as e:
|
270
|
+
PrettyOutput.print(f"数据恢复失败: {e}", OutputType.ERROR)
|
271
|
+
|
272
|
+
return True
|
273
|
+
|
274
|
+
|
187
275
|
def preload_config_for_flags(config_file: Optional[str]) -> None:
|
188
276
|
"""预加载配置(仅用于读取功能开关),不会显示欢迎信息或影响后续 init_env。"""
|
189
277
|
try:
|
@@ -374,6 +462,20 @@ def handle_builtin_config_selector(
|
|
374
462
|
)
|
375
463
|
|
376
464
|
if options:
|
465
|
+
# Add a default option to skip selection
|
466
|
+
options.insert(
|
467
|
+
0,
|
468
|
+
{
|
469
|
+
"category": "skip",
|
470
|
+
"cmd": "",
|
471
|
+
"file": "",
|
472
|
+
"name": "跳过选择 (使用默认通用代理)",
|
473
|
+
"desc": "直接按回车或ESC也可跳过",
|
474
|
+
"details": "",
|
475
|
+
"roles_count": 0,
|
476
|
+
},
|
477
|
+
)
|
478
|
+
|
377
479
|
PrettyOutput.section("可用的内置配置", OutputType.SUCCESS)
|
378
480
|
# 使用 rich Table 呈现
|
379
481
|
table = Table(show_header=True, header_style="bold magenta")
|
@@ -442,35 +544,44 @@ def handle_builtin_config_selector(
|
|
442
544
|
if choice_index != -1:
|
443
545
|
try:
|
444
546
|
sel = options[choice_index]
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
args
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
args
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
547
|
+
# If the "skip" option is chosen, do nothing and proceed to default agent
|
548
|
+
if sel["category"] == "skip":
|
549
|
+
pass
|
550
|
+
else:
|
551
|
+
args: List[str] = []
|
552
|
+
|
553
|
+
if sel["category"] == "agent":
|
554
|
+
# jarvis-agent 支持 -f/--config(全局配置)与 -c/--agent-definition
|
555
|
+
args = [str(sel["cmd"]), "-c", str(sel["file"])]
|
556
|
+
if model_group:
|
557
|
+
args += ["-g", str(model_group)]
|
558
|
+
if config_file:
|
559
|
+
args += ["-f", str(config_file)]
|
560
|
+
if task:
|
561
|
+
args += ["--task", str(task)]
|
562
|
+
|
563
|
+
elif sel["category"] == "multi_agent":
|
564
|
+
# jarvis-multi-agent 需要 -c/--config,用户输入通过 -i/--input 传递
|
565
|
+
args = [str(sel["cmd"]), "-c", str(sel["file"])]
|
566
|
+
if task:
|
567
|
+
args += ["-i", str(task)]
|
568
|
+
|
569
|
+
elif sel["category"] == "roles":
|
570
|
+
# jarvis-platform-manager role 子命令,支持 -c/-t/-g
|
571
|
+
args = [
|
572
|
+
str(sel["cmd"]),
|
573
|
+
"role",
|
574
|
+
"-c",
|
575
|
+
str(sel["file"]),
|
576
|
+
]
|
577
|
+
if model_group:
|
578
|
+
args += ["-g", str(model_group)]
|
579
|
+
|
580
|
+
if args:
|
581
|
+
PrettyOutput.print(
|
582
|
+
f"正在启动: {' '.join(args)}", OutputType.INFO
|
583
|
+
)
|
584
|
+
os.execvp(args[0], args)
|
474
585
|
except Exception:
|
475
586
|
# 任何异常都不影响默认流程
|
476
587
|
pass
|
@@ -521,6 +632,12 @@ def run_cli(
|
|
521
632
|
"--disable-methodology-analysis",
|
522
633
|
help="禁用方法论和任务分析(覆盖配置文件设置)",
|
523
634
|
),
|
635
|
+
backup_data: bool = typer.Option(
|
636
|
+
False, "--backup-data", help="备份 Jarvis 数据目录 (~/.jarvis)"
|
637
|
+
),
|
638
|
+
restore_data: Optional[str] = typer.Option(
|
639
|
+
None, "--restore-data", help="从指定的压缩包恢复 Jarvis 数据"
|
640
|
+
),
|
524
641
|
) -> None:
|
525
642
|
"""Jarvis AI assistant command-line interface."""
|
526
643
|
if ctx.invoked_subcommand is not None:
|
@@ -529,6 +646,14 @@ def run_cli(
|
|
529
646
|
# 使用 rich 输出命令与快捷方式总览
|
530
647
|
print_commands_overview()
|
531
648
|
|
649
|
+
# 处理数据备份
|
650
|
+
if handle_backup_option(backup_data):
|
651
|
+
return
|
652
|
+
|
653
|
+
# 处理数据恢复
|
654
|
+
if handle_restore_option(restore_data, config_file):
|
655
|
+
return
|
656
|
+
|
532
657
|
# 处理配置文件编辑
|
533
658
|
if handle_edit_option(edit, config_file):
|
534
659
|
return
|
jarvis/jarvis_agent/run_loop.py
CHANGED
@@ -7,6 +7,7 @@ AgentRunLoop: 承载 Agent 的主运行循环逻辑。
|
|
7
7
|
- 暂不变更外部调用入口,后续在 Agent._main_loop 中委派到该类
|
8
8
|
- 保持与现有异常处理、工具调用、用户交互完全一致
|
9
9
|
"""
|
10
|
+
import os
|
10
11
|
from enum import Enum
|
11
12
|
from typing import Any, TYPE_CHECKING
|
12
13
|
|
@@ -22,6 +23,8 @@ if TYPE_CHECKING:
|
|
22
23
|
class AgentRunLoop:
|
23
24
|
def __init__(self, agent: "Agent") -> None:
|
24
25
|
self.agent = agent
|
26
|
+
self.conversation_rounds = 0
|
27
|
+
self.tool_reminder_rounds = int(os.environ.get("JARVIS_TOOL_REMINDER_ROUNDS", 20))
|
25
28
|
|
26
29
|
def run(self) -> Any:
|
27
30
|
"""主运行循环(委派到传入的 agent 实例的方法与属性)"""
|
@@ -29,6 +32,12 @@ class AgentRunLoop:
|
|
29
32
|
|
30
33
|
while True:
|
31
34
|
try:
|
35
|
+
self.conversation_rounds += 1
|
36
|
+
if self.conversation_rounds % self.tool_reminder_rounds == 0:
|
37
|
+
self.agent.session.addon_prompt = join_prompts(
|
38
|
+
[self.agent.session.addon_prompt, self.agent.get_tool_usage_prompt()]
|
39
|
+
)
|
40
|
+
|
32
41
|
ag = self.agent
|
33
42
|
|
34
43
|
# 更新输入处理器标志
|
@@ -14,6 +14,7 @@ import typer
|
|
14
14
|
from jarvis.jarvis_agent import Agent
|
15
15
|
from jarvis.jarvis_agent.events import AFTER_TOOL_CALL
|
16
16
|
from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
|
17
|
+
from jarvis.jarvis_agent.file_context_handler import file_context_handler
|
17
18
|
from jarvis.jarvis_agent.edit_file_handler import EditFileHandler
|
18
19
|
from jarvis.jarvis_agent.shell_input_handler import shell_input_handler
|
19
20
|
from jarvis.jarvis_code_agent.lint import get_lint_tools
|
@@ -89,7 +90,11 @@ class CodeAgent:
|
|
89
90
|
auto_complete=False,
|
90
91
|
output_handler=[tool_registry, EditFileHandler()], # type: ignore
|
91
92
|
model_group=model_group,
|
92
|
-
input_handler=[
|
93
|
+
input_handler=[
|
94
|
+
shell_input_handler,
|
95
|
+
file_context_handler,
|
96
|
+
builtin_input_handler,
|
97
|
+
],
|
93
98
|
need_summary=need_summary,
|
94
99
|
use_methodology=False, # 禁用方法论
|
95
100
|
use_analysis=False, # 禁用分析
|
@@ -312,6 +312,11 @@
|
|
312
312
|
"description": "是否启用立即中断:在对话迭代中检测到中断信号时立即返回",
|
313
313
|
"default": false
|
314
314
|
},
|
315
|
+
"JARVIS_SAVE_SESSION_HISTORY": {
|
316
|
+
"type": "boolean",
|
317
|
+
"description": "是否保存会话记录",
|
318
|
+
"default": false
|
319
|
+
},
|
315
320
|
"JARVIS_GIT_CHECK_MODE": {
|
316
321
|
"type": "string",
|
317
322
|
"enum": ["strict", "warn"],
|
@@ -154,9 +154,30 @@ content: |2
|
|
154
154
|
PrettyOutput.print(f"未知消息类型: {type(msg)}", OutputType.WARNING)
|
155
155
|
break
|
156
156
|
|
157
|
+
# Generate a brief summary via direct model call to avoid run-loop recursion
|
158
|
+
try:
|
159
|
+
# 参照 Agent.generate_summary 的实现思路:基于当前 session.prompt 追加请求提示,直接调用底层模型
|
160
|
+
multi_agent_summary_prompt = """
|
161
|
+
请基于当前会话,为即将发送给其他智能体的协作交接写一段摘要,包含:
|
162
|
+
- 已完成的主要工作与产出
|
163
|
+
- 关键决策及其理由
|
164
|
+
- 已知的约束/风险/边界条件
|
165
|
+
- 未解决的问题与待澄清点
|
166
|
+
- 下一步建议与对目标智能体的具体请求
|
167
|
+
要求:
|
168
|
+
- 仅输出纯文本,不包含任何指令或工具调用
|
169
|
+
- 使用简洁的要点式表述
|
170
|
+
""".strip()
|
171
|
+
summary_any: Any = agent.model.chat_until_success( # type: ignore[attr-defined]
|
172
|
+
f"{agent.session.prompt}\n{multi_agent_summary_prompt}"
|
173
|
+
)
|
174
|
+
summary_text = summary_any.strip() if isinstance(summary_any, str) else ""
|
175
|
+
except Exception:
|
176
|
+
summary_text = ""
|
157
177
|
prompt = f"""
|
158
178
|
Please handle this message:
|
159
179
|
from: {last_agent_name}
|
180
|
+
summary_of_sender_work: {summary_text}
|
160
181
|
content: {msg['content']}
|
161
182
|
"""
|
162
183
|
to_agent_name = msg.get("to")
|
jarvis/jarvis_platform/base.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
import re
|
3
|
+
import os
|
4
|
+
from datetime import datetime
|
3
5
|
from abc import ABC, abstractmethod
|
4
6
|
from types import TracebackType
|
5
7
|
from typing import Dict, Generator, List, Optional, Tuple, Type
|
@@ -17,6 +19,8 @@ from jarvis.jarvis_utils.config import (
|
|
17
19
|
get_pretty_output,
|
18
20
|
is_print_prompt,
|
19
21
|
is_immediate_abort,
|
22
|
+
is_save_session_history,
|
23
|
+
get_data_dir,
|
20
24
|
)
|
21
25
|
from jarvis.jarvis_utils.embedding import split_text_into_chunks
|
22
26
|
from jarvis.jarvis_utils.globals import set_in_chat, get_interrupt, console
|
@@ -34,6 +38,7 @@ class BasePlatform(ABC):
|
|
34
38
|
self.web = False # 添加web属性,默认false
|
35
39
|
self._saved = False
|
36
40
|
self.model_group: Optional[str] = None
|
41
|
+
self._session_history_file: Optional[str] = None
|
37
42
|
|
38
43
|
def __enter__(self) -> Self:
|
39
44
|
"""Enter context manager"""
|
@@ -57,6 +62,7 @@ class BasePlatform(ABC):
|
|
57
62
|
def reset(self):
|
58
63
|
"""Reset model"""
|
59
64
|
self.delete_chat()
|
65
|
+
self._session_history_file = None
|
60
66
|
|
61
67
|
@abstractmethod
|
62
68
|
def chat(self, message: str) -> Generator[str, None, None]:
|
@@ -135,6 +141,7 @@ class BasePlatform(ABC):
|
|
135
141
|
if first_chunk:
|
136
142
|
break
|
137
143
|
except StopIteration:
|
144
|
+
self._append_session_history(message, "")
|
138
145
|
return ""
|
139
146
|
|
140
147
|
text_content = Text(overflow="fold")
|
@@ -200,6 +207,7 @@ class BasePlatform(ABC):
|
|
200
207
|
live.update(panel)
|
201
208
|
|
202
209
|
if is_immediate_abort() and get_interrupt():
|
210
|
+
self._append_session_history(message, response)
|
203
211
|
return response # Return the partial response immediately
|
204
212
|
|
205
213
|
# Ensure any remaining content in the buffer is displayed
|
@@ -225,6 +233,7 @@ class BasePlatform(ABC):
|
|
225
233
|
console.print(s, end="")
|
226
234
|
response += s
|
227
235
|
if is_immediate_abort() and get_interrupt():
|
236
|
+
self._append_session_history(message, response)
|
228
237
|
return response
|
229
238
|
console.print()
|
230
239
|
end_time = time.time()
|
@@ -234,6 +243,7 @@ class BasePlatform(ABC):
|
|
234
243
|
for s in self.chat(message):
|
235
244
|
response += s
|
236
245
|
if is_immediate_abort() and get_interrupt():
|
246
|
+
self._append_session_history(message, response)
|
237
247
|
return response
|
238
248
|
# Keep original think tag handling
|
239
249
|
response = re.sub(
|
@@ -242,6 +252,8 @@ class BasePlatform(ABC):
|
|
242
252
|
response = re.sub(
|
243
253
|
ot("thinking") + r".*?" + ct("thinking"), "", response, flags=re.DOTALL
|
244
254
|
)
|
255
|
+
# Save session history (input and full response)
|
256
|
+
self._append_session_history(message, response)
|
245
257
|
return response
|
246
258
|
|
247
259
|
def chat_until_success(self, message: str) -> str:
|
@@ -346,6 +358,51 @@ class BasePlatform(ABC):
|
|
346
358
|
"""Set web flag"""
|
347
359
|
self.web = web
|
348
360
|
|
361
|
+
def _append_session_history(self, user_input: str, model_output: str) -> None:
|
362
|
+
"""
|
363
|
+
Append the user input and model output to a session history file if enabled.
|
364
|
+
The file name is generated on first save and reused until reset.
|
365
|
+
"""
|
366
|
+
try:
|
367
|
+
if not is_save_session_history():
|
368
|
+
return
|
369
|
+
|
370
|
+
if self._session_history_file is None:
|
371
|
+
# Ensure data directory exists
|
372
|
+
data_dir = get_data_dir()
|
373
|
+
os.makedirs(data_dir, exist_ok=True)
|
374
|
+
|
375
|
+
# Build a safe filename including platform, model and timestamp
|
376
|
+
try:
|
377
|
+
platform_name = type(self).platform_name()
|
378
|
+
except Exception:
|
379
|
+
platform_name = "unknown_platform"
|
380
|
+
|
381
|
+
try:
|
382
|
+
model_name = self.name()
|
383
|
+
except Exception:
|
384
|
+
model_name = "unknown_model"
|
385
|
+
|
386
|
+
safe_platform = re.sub(r"[^\w\-\.]+", "_", str(platform_name))
|
387
|
+
safe_model = re.sub(r"[^\w\-\.]+", "_", str(model_name))
|
388
|
+
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
389
|
+
|
390
|
+
self._session_history_file = os.path.join(
|
391
|
+
data_dir, f"session_history_{safe_platform}_{safe_model}_{ts}.log"
|
392
|
+
)
|
393
|
+
|
394
|
+
# Append record
|
395
|
+
with open(self._session_history_file, "a", encoding="utf-8", errors="ignore") as f:
|
396
|
+
ts_line = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
397
|
+
f.write(f"===== {ts_line} =====\n")
|
398
|
+
f.write("USER:\n")
|
399
|
+
f.write(f"{user_input}\n")
|
400
|
+
f.write("\nASSISTANT:\n")
|
401
|
+
f.write(f"{model_output}\n\n")
|
402
|
+
except Exception:
|
403
|
+
# Do not break chat flow if writing history fails
|
404
|
+
pass
|
405
|
+
|
349
406
|
@abstractmethod
|
350
407
|
def support_web(self) -> bool:
|
351
408
|
"""Check if platform supports web functionality"""
|
jarvis/jarvis_platform/openai.py
CHANGED
@@ -24,7 +24,32 @@ class OpenAIModel(BasePlatform):
|
|
24
24
|
self.base_url = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
|
25
25
|
self.model_name = os.getenv("JARVIS_MODEL") or "gpt-4o"
|
26
26
|
|
27
|
-
|
27
|
+
# Optional: Inject extra HTTP headers via environment variable
|
28
|
+
# Expected format: OPENAI_EXTRA_HEADERS='{"Header-Name": "value", "X-Trace": "abc"}'
|
29
|
+
headers_str = os.getenv("OPENAI_EXTRA_HEADERS")
|
30
|
+
self.extra_headers: Dict[str, str] = {}
|
31
|
+
if headers_str:
|
32
|
+
try:
|
33
|
+
parsed = json.loads(headers_str)
|
34
|
+
if isinstance(parsed, dict):
|
35
|
+
# Ensure all header keys/values are strings
|
36
|
+
self.extra_headers = {str(k): str(v) for k, v in parsed.items()}
|
37
|
+
else:
|
38
|
+
PrettyOutput.print("OPENAI_EXTRA_HEADERS 应为 JSON 对象,如 {'X-Source':'jarvis'}", OutputType.WARNING)
|
39
|
+
except Exception as e:
|
40
|
+
PrettyOutput.print(f"解析 OPENAI_EXTRA_HEADERS 失败: {e}", OutputType.WARNING)
|
41
|
+
|
42
|
+
# Initialize OpenAI client, try to pass default headers if SDK supports it
|
43
|
+
try:
|
44
|
+
if self.extra_headers:
|
45
|
+
self.client = OpenAI(api_key=self.api_key, base_url=self.base_url, default_headers=self.extra_headers)
|
46
|
+
else:
|
47
|
+
self.client = OpenAI(api_key=self.api_key, base_url=self.base_url)
|
48
|
+
except TypeError:
|
49
|
+
# Fallback: SDK version may not support default_headers
|
50
|
+
self.client = OpenAI(api_key=self.api_key, base_url=self.base_url)
|
51
|
+
if self.extra_headers:
|
52
|
+
PrettyOutput.print("当前 OpenAI SDK 不支持 default_headers,未能注入额外 HTTP 头", OutputType.WARNING)
|
28
53
|
self.messages: List[Dict[str, str]] = []
|
29
54
|
self.system_message = ""
|
30
55
|
|
jarvis/jarvis_tools/edit_file.py
CHANGED
@@ -34,17 +34,18 @@ class FileSearchReplaceTool:
|
|
34
34
|
- REPLACE: 替换后的新代码
|
35
35
|
- 区间替换:
|
36
36
|
- reason: 修改原因描述
|
37
|
-
- SEARCH_START:
|
38
|
-
- SEARCH_END:
|
37
|
+
- SEARCH_START: 起始标记
|
38
|
+
- SEARCH_END: 结束标记
|
39
39
|
- REPLACE: 替换后的新代码
|
40
40
|
- RANGE: 可选的行号范围 'start-end' (1-based, 闭区间), 用于限定匹配范围
|
41
|
+
- **说明**: 区间替换会从包含 SEARCH_START 的行首开始,到包含 SEARCH_END 的行尾结束,替换整个区域
|
41
42
|
|
42
43
|
## 核心原则
|
43
44
|
1. **精准修改**: 只修改必要的代码部分,保持其他部分不变
|
44
45
|
2. **最小补丁原则**: 生成最小范围的补丁,包含必要的上下文
|
45
46
|
3. **唯一匹配**:
|
46
47
|
- 单点替换:确保 SEARCH 在文件中唯一匹配
|
47
|
-
-
|
48
|
+
- 区间替换:确保在指定范围内,第一个 SEARCH_START 之后能找到 SEARCH_END
|
48
49
|
4. **格式保持**: 严格保持原始代码的格式风格
|
49
50
|
5. **部分成功**: 支持多个文件编辑,允许部分文件编辑成功
|
50
51
|
|
@@ -121,11 +122,10 @@ class FileSearchReplaceTool:
|
|
121
122
|
- REPLACE: 替换后的新代码
|
122
123
|
2) 区间替换:
|
123
124
|
- reason: 修改原因描述
|
124
|
-
- SEARCH_START:
|
125
|
-
- SEARCH_END:
|
125
|
+
- SEARCH_START: 起始标记
|
126
|
+
- SEARCH_END: 结束标记
|
126
127
|
- REPLACE: 替换后的新代码
|
127
|
-
|
128
|
-
- RANGE: 形如 'start-end'(1-based,闭区间),仅用于区间替换模式。当提供时仅在该行号范围内执行匹配与替换;省略则在整个文件范围内处理
|
128
|
+
- **说明**: 区间替换会从包含 SEARCH_START 的行首开始,到包含 SEARCH_END 的行尾结束,替换整个区域
|
129
129
|
|
130
130
|
返回:
|
131
131
|
Dict[str, Any] 包含:
|
@@ -58,7 +58,8 @@ class WebpageTool:
|
|
58
58
|
2. 包含网页标题
|
59
59
|
3. 根据用户需求提供准确、完整的信息"""
|
60
60
|
response = model.chat_until_success(prompt) # type: ignore
|
61
|
-
|
61
|
+
if response and response.strip():
|
62
|
+
return {"success": True, "stdout": response, "stderr": ""}
|
62
63
|
|
63
64
|
# 2) 然后尝试使用默认平台(normal)的 web 能力
|
64
65
|
model = PlatformRegistry().get_normal_platform()
|
@@ -73,7 +74,8 @@ class WebpageTool:
|
|
73
74
|
2. 包含网页标题
|
74
75
|
3. 根据用户需求提供准确、完整的信息"""
|
75
76
|
response = model.chat_until_success(prompt) # type: ignore
|
76
|
-
|
77
|
+
if response and response.strip():
|
78
|
+
return {"success": True, "stdout": response, "stderr": ""}
|
77
79
|
|
78
80
|
# 3) 回退:使用 requests 抓取网页,再用模型分析
|
79
81
|
|
@@ -147,11 +147,13 @@ class SearchWebTool:
|
|
147
147
|
if model.support_web():
|
148
148
|
model.set_web(True)
|
149
149
|
model.set_suppress_output(False)
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
150
|
+
response = model.chat_until_success(query)
|
151
|
+
if response and response.strip():
|
152
|
+
return {
|
153
|
+
"stdout": response,
|
154
|
+
"stderr": "",
|
155
|
+
"success": True,
|
156
|
+
}
|
155
157
|
|
156
158
|
# 否则使用现有的模型选择流程
|
157
159
|
if agent.model.support_web():
|
@@ -161,11 +163,13 @@ class SearchWebTool:
|
|
161
163
|
model.set_model_name(agent.model.name())
|
162
164
|
model.set_web(True)
|
163
165
|
model.set_suppress_output(False)
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
166
|
+
response = model.chat_until_success(query)
|
167
|
+
if response and response.strip():
|
168
|
+
return {
|
169
|
+
"stdout": response,
|
170
|
+
"stderr": "",
|
171
|
+
"success": True,
|
172
|
+
}
|
169
173
|
|
170
174
|
return self._search_with_ddgs(query, agent)
|
171
175
|
|
jarvis/jarvis_utils/config.py
CHANGED
@@ -730,6 +730,16 @@ def is_enable_builtin_config_selector() -> bool:
|
|
730
730
|
)
|
731
731
|
|
732
732
|
|
733
|
+
def is_save_session_history() -> bool:
|
734
|
+
"""
|
735
|
+
是否保存会话记录。
|
736
|
+
|
737
|
+
返回:
|
738
|
+
bool: 如果要保存会话记录则返回True, 默认为False
|
739
|
+
"""
|
740
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_SAVE_SESSION_HISTORY", False) is True
|
741
|
+
|
742
|
+
|
733
743
|
def is_immediate_abort() -> bool:
|
734
744
|
"""
|
735
745
|
是否启用立即中断:当在对话过程中检测到用户中断信号时,立即停止输出并返回。
|
jarvis/jarvis_utils/git_utils.py
CHANGED
@@ -299,7 +299,7 @@ def get_modified_line_ranges() -> Dict[str, List[Tuple[int, int]]]:
|
|
299
299
|
# 获取所有文件的Git差异
|
300
300
|
# 仅用于解析修改行范围,减少上下文以降低输出体积和解析成本
|
301
301
|
result = subprocess.run(
|
302
|
-
["git", "show", "
|
302
|
+
["git", "show", "--no-color"],
|
303
303
|
capture_output=True,
|
304
304
|
text=True,
|
305
305
|
)
|
jarvis/jarvis_utils/input.py
CHANGED
@@ -482,7 +482,7 @@ def _get_multiline_input_internal(
|
|
482
482
|
"""Handle Ctrl+O by exiting the prompt and returning the sentinel value."""
|
483
483
|
event.app.exit(result=CTRL_O_SENTINEL)
|
484
484
|
|
485
|
-
@bindings.add("c-t", filter=has_focus(DEFAULT_BUFFER))
|
485
|
+
@bindings.add("c-t", filter=has_focus(DEFAULT_BUFFER), eager=True)
|
486
486
|
def _(event):
|
487
487
|
"""Return a shell command like '!bash' for upper input_handler to execute."""
|
488
488
|
|
jarvis/jarvis_utils/utils.py
CHANGED
@@ -1719,11 +1719,11 @@ def while_success(func: Callable[[], Any], sleep_time: float = 0.1, max_retries:
|
|
1719
1719
|
try:
|
1720
1720
|
result = func()
|
1721
1721
|
break
|
1722
|
-
except Exception:
|
1722
|
+
except Exception as e:
|
1723
1723
|
retry_count += 1
|
1724
1724
|
if retry_count < max_retries:
|
1725
1725
|
PrettyOutput.print(
|
1726
|
-
f"
|
1726
|
+
f"发生异常:\n{e}\n重试中 ({retry_count}/{max_retries}),等待 {sleep_time}s...",
|
1727
1727
|
OutputType.WARNING,
|
1728
1728
|
)
|
1729
1729
|
time.sleep(sleep_time)
|
@@ -1,14 +1,15 @@
|
|
1
|
-
jarvis/__init__.py,sha256=
|
1
|
+
jarvis/__init__.py,sha256=pK5l6XHBkpMUJjvRS5nGlvLwpzdLLQEAyFtF-qstkkM,74
|
2
2
|
jarvis/jarvis_agent/__init__.py,sha256=Mp0lcivL99cL2eIjHz-D1C86XMOhJkFYtnQcJoflfH4,49033
|
3
|
-
jarvis/jarvis_agent/agent_manager.py,sha256=
|
3
|
+
jarvis/jarvis_agent/agent_manager.py,sha256=UgMUz6fSV2XhQHhmIGHF53MyUytAPvZ1yC2f29LcTO8,3235
|
4
4
|
jarvis/jarvis_agent/builtin_input_handler.py,sha256=wS-FqpT3pIXwHn1dfL3SpXonUKWgVThbQueUIeyRc2U,2917
|
5
5
|
jarvis/jarvis_agent/config.py,sha256=Ni1aTVzmdERJ89A1jsC21Tsys_9MM-TTx1w5XwxyEwA,3130
|
6
6
|
jarvis/jarvis_agent/config_editor.py,sha256=hlb9EYxKWcR_qdW2O89CgNDdciR9Isi743JU_1gD8j4,1927
|
7
|
-
jarvis/jarvis_agent/edit_file_handler.py,sha256=
|
7
|
+
jarvis/jarvis_agent/edit_file_handler.py,sha256=7xkEvlER6pNHtxyGad_ol23NeDGsYMunq4XmTAx86kw,24722
|
8
8
|
jarvis/jarvis_agent/event_bus.py,sha256=pRdfk7d0OG18K6yNfWlCvAh_dW5p9sBtT2Yc3jGmzgo,1519
|
9
9
|
jarvis/jarvis_agent/events.py,sha256=rmFQ37PasImCh7OCdCzNBvubk-kHwcUiYLgzmL0t0_4,3689
|
10
|
+
jarvis/jarvis_agent/file_context_handler.py,sha256=2MPn_O_2llX39meFg272Cjk3wMPn5nmgbGMUyX06YQo,2113
|
10
11
|
jarvis/jarvis_agent/file_methodology_manager.py,sha256=LnhgTx5xQXCBK8esjCkFbgFm9iEyFX7TryUlC40Kzpw,4428
|
11
|
-
jarvis/jarvis_agent/jarvis.py,sha256=
|
12
|
+
jarvis/jarvis_agent/jarvis.py,sha256=CNuVLxbl9erQkEq41oWI7tFGi-AMiNBEJ56alQLm_m4,29111
|
12
13
|
jarvis/jarvis_agent/main.py,sha256=bFcwXWC6O05jQiXy6ED_bHjdjDo5VwV_i1BoBEAzgP0,3336
|
13
14
|
jarvis/jarvis_agent/memory_manager.py,sha256=WSyUffx9xTmkcj4QrSLEfsjI3sTMUwZmkkC9_N_gTjo,8042
|
14
15
|
jarvis/jarvis_agent/methodology_share_manager.py,sha256=AB_J9BwRgaeENQfL6bH83FOLeLrgHhppMb7psJNevKs,6874
|
@@ -17,7 +18,7 @@ jarvis/jarvis_agent/prompt_builder.py,sha256=PH1fPDVa8z_RXkoXHJFNDf8PQjUoLNLYwkh
|
|
17
18
|
jarvis/jarvis_agent/prompt_manager.py,sha256=_1qLBSA3yn4nT_N3X2npTpW40Cp-pMeyvnzu-pnG0iU,2720
|
18
19
|
jarvis/jarvis_agent/prompts.py,sha256=CvbPYx_klEz6OQrxVReZAnC2uQNo53rWkkucmh30uKg,9531
|
19
20
|
jarvis/jarvis_agent/protocols.py,sha256=YFJaC9MHi7JfLzmvlyotJDjiCO4Z07XJXy1gKhVdUy4,956
|
20
|
-
jarvis/jarvis_agent/run_loop.py,sha256=
|
21
|
+
jarvis/jarvis_agent/run_loop.py,sha256=OWdJSq1dLC6xPx4EQBfSnD_rb3IwszwZp4KbXYiJtcg,4747
|
21
22
|
jarvis/jarvis_agent/session_manager.py,sha256=5wVcaZGwJ9cEKTQglSbqyxUDJ2fI5KxYN8C8L16UWLw,3024
|
22
23
|
jarvis/jarvis_agent/share_manager.py,sha256=MF2RlomcgPxF8nVUk28DP6IRddZ_tot5l_YRvy0qXSQ,8726
|
23
24
|
jarvis/jarvis_agent/shell_input_handler.py,sha256=wiAPjB-9uTkcLszbO5dlOUwIfaeR39RgRcZhahIGqoA,2018
|
@@ -28,7 +29,7 @@ jarvis/jarvis_agent/tool_share_manager.py,sha256=Do08FRxis0ynwR2a6iRoa6Yq0qCP8Nk
|
|
28
29
|
jarvis/jarvis_agent/user_interaction.py,sha256=tifFN49GkO_Q80sqOTVmhxwbNWTazF3K0cr8AnnvzdU,1453
|
29
30
|
jarvis/jarvis_agent/utils.py,sha256=ldgfuNTNu4JU7Y1LtystBl85OC6H3A4OMycg0XBt_Cs,1615
|
30
31
|
jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
31
|
-
jarvis/jarvis_code_agent/code_agent.py,sha256=
|
32
|
+
jarvis/jarvis_code_agent/code_agent.py,sha256=lAnVTFxnnOsd2Vih9c-nSuczfz6CKTMhUQnhj8UcwWk,36735
|
32
33
|
jarvis/jarvis_code_agent/lint.py,sha256=_qLJB_bC3PuoHG-j4EGOnYzNGO26jHlKLbkysfyQW1c,3954
|
33
34
|
jarvis/jarvis_code_analysis/code_review.py,sha256=Z0JsvyVPPHPm6rfo4fqaQr7CdZKIllo9jqStzV0i_-o,34470
|
34
35
|
jarvis/jarvis_code_analysis/checklists/__init__.py,sha256=LIXAYa1sW3l7foP6kohLWnE98I_EQ0T7z5bYKHq6rJA,78
|
@@ -51,7 +52,7 @@ jarvis/jarvis_code_analysis/checklists/shell.py,sha256=aRFYhQQvTgbYd-uY5pc8UHIUA
|
|
51
52
|
jarvis/jarvis_code_analysis/checklists/sql.py,sha256=vR0T6qC7b4dURjJVAd7kSVxyvZEQXPG1Jqc2sNTGp5c,2355
|
52
53
|
jarvis/jarvis_code_analysis/checklists/swift.py,sha256=TPx4I6Gupvs6tSerRKmTSKEPQpOLEbH2Y7LXg1uBgxc,2566
|
53
54
|
jarvis/jarvis_code_analysis/checklists/web.py,sha256=25gGD7pDadZQybNFvALYxWvK0VRjGQb1NVJQElwjyk0,3943
|
54
|
-
jarvis/jarvis_data/config_schema.json,sha256=
|
55
|
+
jarvis/jarvis_data/config_schema.json,sha256=K6Q4ltnULhIVqYTLUSIyiGcZiOaMwkpbhUXQ4U-kDqI,14307
|
55
56
|
jarvis/jarvis_data/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4,sha256=Ijkht27pm96ZW3_3OFE-7xAPtR0YyTWXoRO8_-hlsqc,1681126
|
56
57
|
jarvis/jarvis_git_squash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
57
58
|
jarvis/jarvis_git_squash/main.py,sha256=BRbsEQVXwseVFKliVqV8_JPh1om6QT6dLTHw0jQ7OE0,2474
|
@@ -63,14 +64,14 @@ jarvis/jarvis_mcp/streamable_mcp_client.py,sha256=BenOeZGNHdUOJT5Z3cc5MhS6aOeKQg
|
|
63
64
|
jarvis/jarvis_memory_organizer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
64
65
|
jarvis/jarvis_memory_organizer/memory_organizer.py,sha256=CMFL46vvtpcTI6oS3CAlYteR6xAlwCkvVJmMT22uDRw,26295
|
65
66
|
jarvis/jarvis_methodology/main.py,sha256=uiNzk5b5O6xdvRhsOuD7ubxdd2tPcDsFFnvmes8uH8I,11370
|
66
|
-
jarvis/jarvis_multi_agent/__init__.py,sha256=
|
67
|
+
jarvis/jarvis_multi_agent/__init__.py,sha256=fBWmW5S9gpEEYzCBJizyE2q0Jj2LUzj4yh7sfoe3Qrc,7170
|
67
68
|
jarvis/jarvis_multi_agent/main.py,sha256=b9IThFMeUZCYSlgT-VT8r7xeBdrEE_zNT11awEc8IdY,1853
|
68
69
|
jarvis/jarvis_platform/__init__.py,sha256=WLQHSiE87PPket2M50_hHzjdMIgPIBx2VF8JfB_NNRk,105
|
69
70
|
jarvis/jarvis_platform/ai8.py,sha256=g8JkqPGs9SEbqstNMCc5rCHO0QcPHX9LNvb7HMWwB-Q,11471
|
70
|
-
jarvis/jarvis_platform/base.py,sha256=
|
71
|
+
jarvis/jarvis_platform/base.py,sha256=NhhiAiACNsL462zljtGsG61SD8X-RRJyOAz1n1ocAPw,15947
|
71
72
|
jarvis/jarvis_platform/human.py,sha256=jWjW8prEag79e6ddqTPV4nz_Gz6zFBfO4a1EbvP8QWA,4908
|
72
73
|
jarvis/jarvis_platform/kimi.py,sha256=KLsf9udAsPRMbQ2JkBeiAlXkupCBwdtMaJ-hpH4Jdkc,15711
|
73
|
-
jarvis/jarvis_platform/openai.py,sha256=
|
74
|
+
jarvis/jarvis_platform/openai.py,sha256=4YapmkmJmPGfrjktORcIejlB98b83Wsi_48zjBymHAc,9500
|
74
75
|
jarvis/jarvis_platform/registry.py,sha256=YqaFM2LXcHvqMQrTEQ_cVo8V-wQ8HhOeSdC8DdjvC00,8045
|
75
76
|
jarvis/jarvis_platform/tongyi.py,sha256=QQHDn-kNcb_UH-B49lVIQTlHzYd_O8CFWN7SZqy38S4,23456
|
76
77
|
jarvis/jarvis_platform/yuanbao.py,sha256=jlttNWq-Bq9JLxaI6MOsxKZaNEXF1EfVVB7mjtVcYMA,23954
|
@@ -97,18 +98,18 @@ jarvis/jarvis_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
|
|
97
98
|
jarvis/jarvis_tools/ask_user.py,sha256=M6DdLNryCE8y1JcdZHEifUgZkPUEPNKc-zDW5p0Mb1k,2029
|
98
99
|
jarvis/jarvis_tools/base.py,sha256=tFZkRlbV_a-pbjM-ci9AYmXVJm__FXuzVWKbQEyz4Ao,1639
|
99
100
|
jarvis/jarvis_tools/clear_memory.py,sha256=8DOq6dHLemfKTJqu227PWBIp8Iu5K7EXwINzL8DYk8M,8205
|
100
|
-
jarvis/jarvis_tools/edit_file.py,sha256=
|
101
|
+
jarvis/jarvis_tools/edit_file.py,sha256=UcJNTVCDEmRaQsN_7_Ip2LjrTDm4wWzj2deuZHiBvLI,9026
|
101
102
|
jarvis/jarvis_tools/execute_script.py,sha256=oDOMn8GcV6qKP4d0RFT6xbHGTazRmaOlp-h_e_Wj80c,6227
|
102
103
|
jarvis/jarvis_tools/file_analyzer.py,sha256=jzVb8fAJn3dWwpCiYH-Wuxva4kpHqBB2_V3x3mzY0Gs,4158
|
103
104
|
jarvis/jarvis_tools/generate_new_tool.py,sha256=tJz0YtfDwyH9y00VEWw3Btqr9JCNhvtI8BN9i5hYk_M,8560
|
104
105
|
jarvis/jarvis_tools/methodology.py,sha256=_K4GIDUodGEma3SvNRo7Qs5rliijgNespVLyAPN35JU,5233
|
105
106
|
jarvis/jarvis_tools/read_code.py,sha256=F1RuO0c69t0h7CvrUGqrTyNcOCcUrFQPACc61O_YSso,6382
|
106
|
-
jarvis/jarvis_tools/read_webpage.py,sha256=
|
107
|
+
jarvis/jarvis_tools/read_webpage.py,sha256=dfyXJ9vaX-ZRbua1P5ZlaU_SlSzKkeNw-1kI_3-gxFE,5433
|
107
108
|
jarvis/jarvis_tools/registry.py,sha256=yVXBrJ7plyn7Dr3dD6mPmgd6eiBftmd19Cc84-PwVN8,33312
|
108
109
|
jarvis/jarvis_tools/retrieve_memory.py,sha256=hhhGSr7jebPHICY9oEKICyI8mfqsRtKjh58qZNZApKc,8624
|
109
110
|
jarvis/jarvis_tools/rewrite_file.py,sha256=CuvjWPTbUaPbex9FKSmw_Ru4r6R-CX_3vqTqCTp8nHA,6959
|
110
111
|
jarvis/jarvis_tools/save_memory.py,sha256=RQtNxcpU53FFv_EBjH0i0oyQ7jWubm-trD1BHuqaGjI,6985
|
111
|
-
jarvis/jarvis_tools/search_web.py,sha256=
|
112
|
+
jarvis/jarvis_tools/search_web.py,sha256=Hi8WBxcRH02qjOF1qcJP2qSqs3kVOKGFAARfh548Ii4,6370
|
112
113
|
jarvis/jarvis_tools/sub_agent.py,sha256=kjMZBXQE3OUgm5eO9lNkOuBnugWQGZbCpVP0HNW5W2s,8905
|
113
114
|
jarvis/jarvis_tools/sub_code_agent.py,sha256=vVPcGKfgyhbZzl8vp2HHbgR1oQzC0TlS0G3THoZgU5Q,9453
|
114
115
|
jarvis/jarvis_tools/virtual_tty.py,sha256=L7-J00ARQvIa25T45Hhqg2eCBl6W2LFgqDlWMWf-7dk,25275
|
@@ -117,21 +118,21 @@ jarvis/jarvis_tools/cli/main.py,sha256=WL2GNV7WqYl7G1-btRGvCkzDCMk4fPfNvzCrnUFVP
|
|
117
118
|
jarvis/jarvis_utils/__init__.py,sha256=67h0ldisGlh3oK4DAeNEL2Bl_VsI3tSmfclasyVlueM,850
|
118
119
|
jarvis/jarvis_utils/builtin_replace_map.py,sha256=z8iAqsbZUiGFaozxG1xSu128op8udqHOeEw-GxNt4bU,1708
|
119
120
|
jarvis/jarvis_utils/clipboard.py,sha256=D3wzQeqg_yiH7Axs4d6MRxyNa9XxdnenH-ND2uj2WVQ,2967
|
120
|
-
jarvis/jarvis_utils/config.py,sha256=
|
121
|
+
jarvis/jarvis_utils/config.py,sha256=e5S6-H0Up3OupUu0ATESh3UWkjEfsbkyxDf_0fPPBpU,21372
|
121
122
|
jarvis/jarvis_utils/embedding.py,sha256=x6mrkL7Bc3qgfuBDsjc4fg4nKG8ofGxVLVVydbsb8PY,2838
|
122
123
|
jarvis/jarvis_utils/file_processors.py,sha256=XiM248SHS7lLgQDCbORVFWqinbVDUawYxWDOsLXDxP8,3043
|
123
124
|
jarvis/jarvis_utils/fzf.py,sha256=vCs0Uh5dUqGbWzXn2JCtLLCOYE2B39ZNdNveR9PK4DA,1681
|
124
|
-
jarvis/jarvis_utils/git_utils.py,sha256=
|
125
|
+
jarvis/jarvis_utils/git_utils.py,sha256=zxjdxbFb_X6aYo-w1fbMx3d2n1ScbmmaAYlE3wGaaSg,24071
|
125
126
|
jarvis/jarvis_utils/globals.py,sha256=7Xvf9HY6jYJL4vSD1F1WCoxHkHCAyltJUYt4V9gGVU4,8865
|
126
127
|
jarvis/jarvis_utils/http.py,sha256=eRhV3-GYuWmQ0ogq9di9WMlQkFcVb1zGCrySnOgT1x0,4392
|
127
|
-
jarvis/jarvis_utils/input.py,sha256=
|
128
|
+
jarvis/jarvis_utils/input.py,sha256=BT-aAaOBFsb4YeqR5ceIsa-j_MYEmsAvQqrXQSknA7c,36536
|
128
129
|
jarvis/jarvis_utils/methodology.py,sha256=z_renvRGgHiC-XTQPuN6rvrJ_ffHlwxK_b1BU_jmNAQ,12800
|
129
130
|
jarvis/jarvis_utils/output.py,sha256=y2fVcao_2ZowFl0IxUrJZCi8T6ZM0z-iPzpk8T8eLxc,13623
|
130
131
|
jarvis/jarvis_utils/tag.py,sha256=f211opbbbTcSyzCDwuIK_oCnKhXPNK-RknYyGzY1yD0,431
|
131
|
-
jarvis/jarvis_utils/utils.py,sha256=
|
132
|
-
jarvis_ai_assistant-0.3.
|
133
|
-
jarvis_ai_assistant-0.3.
|
134
|
-
jarvis_ai_assistant-0.3.
|
135
|
-
jarvis_ai_assistant-0.3.
|
136
|
-
jarvis_ai_assistant-0.3.
|
137
|
-
jarvis_ai_assistant-0.3.
|
132
|
+
jarvis/jarvis_utils/utils.py,sha256=uMtfaStxDtp2i9AFIxwtPKgSxLwQxw8Z2rXsX-ZGlis,72728
|
133
|
+
jarvis_ai_assistant-0.3.33.dist-info/licenses/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
|
134
|
+
jarvis_ai_assistant-0.3.33.dist-info/METADATA,sha256=GnrDTF9-OWDXNJUjGxlbBxUFUXR5ZmWCopRNw6YiVsk,18752
|
135
|
+
jarvis_ai_assistant-0.3.33.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
136
|
+
jarvis_ai_assistant-0.3.33.dist-info/entry_points.txt,sha256=4GcWKFxRJD-QU14gw_3ZaW4KuEVxOcZK9i270rwPdjA,1395
|
137
|
+
jarvis_ai_assistant-0.3.33.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
|
138
|
+
jarvis_ai_assistant-0.3.33.dist-info/RECORD,,
|
File without changes
|
{jarvis_ai_assistant-0.3.31.dist-info → jarvis_ai_assistant-0.3.33.dist-info}/entry_points.txt
RENAMED
File without changes
|
{jarvis_ai_assistant-0.3.31.dist-info → jarvis_ai_assistant-0.3.33.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
File without changes
|