jarvis-ai-assistant 0.1.212__tar.gz → 0.1.214__tar.gz
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_ai_assistant-0.1.212/src/jarvis_ai_assistant.egg-info → jarvis_ai_assistant-0.1.214}/PKG-INFO +2 -2
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/pyproject.toml +2 -2
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/setup.py +4 -3
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/__init__.py +1 -1
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_agent/__init__.py +43 -20
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_agent/builtin_input_handler.py +12 -1
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_agent/edit_file_handler.py +44 -32
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_agent/code_agent.py +10 -4
- jarvis_ai_assistant-0.1.214/src/jarvis/jarvis_platform/ai8.py +309 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_platform/base.py +33 -7
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_platform/human.py +43 -1
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_platform/kimi.py +50 -6
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_platform/openai.py +38 -1
- jarvis_ai_assistant-0.1.214/src/jarvis/jarvis_platform/oyi.py +351 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_platform/tongyi.py +53 -7
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_platform/yuanbao.py +47 -4
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_platform_manager/main.py +65 -19
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_platform_manager/service.py +66 -100
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/input.py +6 -5
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214/src/jarvis_ai_assistant.egg-info}/PKG-INFO +2 -2
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis_ai_assistant.egg-info/requires.txt +1 -1
- jarvis_ai_assistant-0.1.212/src/jarvis/jarvis_platform/ai8.py +0 -270
- jarvis_ai_assistant-0.1.212/src/jarvis/jarvis_platform/oyi.py +0 -314
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/MANIFEST.in +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/README.md +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/setup.cfg +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_agent/jarvis.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_agent/main.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_agent/output_handler.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_agent/shell_input_handler.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_agent/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_agent/lint.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/c_cpp.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/csharp.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/data_format.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/devops.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/docs.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/go.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/infrastructure.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/java.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/javascript.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/kotlin.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/loader.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/php.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/python.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/ruby.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/rust.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/shell.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/sql.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/swift.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/checklists/web.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_code_analysis/code_review.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_data/config_schema.json +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_data/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_git_details/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_git_details/main.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_git_squash/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_git_squash/main.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_git_utils/git_commiter.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_mcp/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_mcp/sse_mcp_client.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_mcp/stdio_mcp_client.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_mcp/streamable_mcp_client.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_methodology/main.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_multi_agent/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_multi_agent/main.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_platform/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_platform/registry.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_platform_manager/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_smart_shell/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_smart_shell/main.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/ask_user.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/base.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/cli/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/cli/main.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/edit_file.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/execute_script.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/file_analyzer.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/generate_new_tool.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/methodology.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/read_code.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/read_webpage.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/registry.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/rewrite_file.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/search_web.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_tools/virtual_tty.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/builtin_replace_map.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/config.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/embedding.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/file_processors.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/git_utils.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/globals.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/http.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/methodology.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/output.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/tag.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_utils/utils.py +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis_ai_assistant.egg-info/SOURCES.txt +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis_ai_assistant.egg-info/dependency_links.txt +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis_ai_assistant.egg-info/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis_ai_assistant.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: jarvis-ai-assistant
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.214
|
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
|
@@ -54,8 +54,8 @@ Requires-Dist: pillow==10.2.0
|
|
54
54
|
Requires-Dist: openai==1.78.1
|
55
55
|
Requires-Dist: tabulate==0.9.0
|
56
56
|
Requires-Dist: pyte==0.8.2
|
57
|
-
Requires-Dist: pyyaml>=6.0.2
|
58
57
|
Requires-Dist: httpx>=0.28.1
|
58
|
+
Requires-Dist: pyyaml>=5.3.1
|
59
59
|
Provides-Extra: dev
|
60
60
|
Requires-Dist: pytest; extra == "dev"
|
61
61
|
Requires-Dist: black; extra == "dev"
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "jarvis-ai-assistant"
|
7
|
-
version = "0.1.
|
7
|
+
version = "0.1.214"
|
8
8
|
description = "Jarvis: An AI assistant that uses tools to interact with the system"
|
9
9
|
readme = "README.md"
|
10
10
|
authors = [{ name = "skyfire", email = "skyfireitdiy@hotmail.com" }]
|
@@ -36,8 +36,8 @@ dependencies = [
|
|
36
36
|
"openai==1.78.1",
|
37
37
|
"tabulate==0.9.0",
|
38
38
|
"pyte==0.8.2",
|
39
|
-
"pyyaml>=6.0.2",
|
40
39
|
"httpx>=0.28.1",
|
40
|
+
"pyyaml>=5.3.1",
|
41
41
|
]
|
42
42
|
requires-python = ">=3.8"
|
43
43
|
|
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages # type: ignore
|
|
3
3
|
|
4
4
|
setup(
|
5
5
|
name="jarvis-ai-assistant",
|
6
|
-
version="0.1.
|
6
|
+
version="0.1.214",
|
7
7
|
author="skyfire",
|
8
8
|
author_email="skyfireitdiy@hotmail.com",
|
9
9
|
description="An AI assistant that uses various tools to interact with the system",
|
@@ -31,10 +31,11 @@ setup(
|
|
31
31
|
"openai==1.78.1",
|
32
32
|
"tabulate==0.9.0",
|
33
33
|
"pyte==0.8.2",
|
34
|
-
"pyyaml>=
|
34
|
+
"pyyaml>=5.3.1",
|
35
35
|
"httpx>=0.28.1",
|
36
36
|
],
|
37
|
-
extras_require={"dev": ["pytest", "black",
|
37
|
+
extras_require={"dev": ["pytest", "black",
|
38
|
+
"isort", "mypy", "build", "twine"]},
|
38
39
|
entry_points={
|
39
40
|
"console_scripts": [
|
40
41
|
"jarvis=jarvis.jarvis_agent.jarvis:main",
|
{jarvis_ai_assistant-0.1.212 → jarvis_ai_assistant-0.1.214}/src/jarvis/jarvis_agent/__init__.py
RENAMED
@@ -119,13 +119,17 @@ origin_agent_system_prompt = f"""
|
|
119
119
|
|
120
120
|
|
121
121
|
class OutputHandlerProtocol(Protocol):
|
122
|
-
def name(self) -> str:
|
122
|
+
def name(self) -> str:
|
123
|
+
...
|
123
124
|
|
124
|
-
def can_handle(self, response: str) -> bool:
|
125
|
+
def can_handle(self, response: str) -> bool:
|
126
|
+
...
|
125
127
|
|
126
|
-
def prompt(self) -> str:
|
128
|
+
def prompt(self) -> str:
|
129
|
+
...
|
127
130
|
|
128
|
-
def handle(self, response: str, agent: Any) -> Tuple[bool, Any]:
|
131
|
+
def handle(self, response: str, agent: Any) -> Tuple[bool, Any]:
|
132
|
+
...
|
129
133
|
|
130
134
|
|
131
135
|
class Agent:
|
@@ -191,9 +195,7 @@ class Agent:
|
|
191
195
|
if isinstance(platform, str):
|
192
196
|
self.model = PlatformRegistry().create_platform(platform)
|
193
197
|
if self.model is None:
|
194
|
-
PrettyOutput.print(
|
195
|
-
f"平台 {platform} 不存在,将使用普通模型", OutputType.WARNING
|
196
|
-
)
|
198
|
+
PrettyOutput.print(f"平台 {platform} 不存在,将使用普通模型", OutputType.WARNING)
|
197
199
|
self.model = PlatformRegistry().get_normal_platform()
|
198
200
|
else:
|
199
201
|
self.model = platform
|
@@ -356,6 +358,33 @@ class Agent:
|
|
356
358
|
"""
|
357
359
|
self.after_tool_call_cb = cb
|
358
360
|
|
361
|
+
def save_session(self) -> bool:
|
362
|
+
"""保存当前会话状态到文件"""
|
363
|
+
if not self.model:
|
364
|
+
PrettyOutput.print("没有可用的模型实例来保存会话。", OutputType.ERROR)
|
365
|
+
return False
|
366
|
+
session_dir = os.path.join(os.getcwd(), ".jarvis")
|
367
|
+
os.makedirs(session_dir, exist_ok=True)
|
368
|
+
session_file = os.path.join(session_dir, "saved_session.json")
|
369
|
+
return self.model.save(session_file)
|
370
|
+
|
371
|
+
def restore_session(self) -> bool:
|
372
|
+
"""从文件恢复会话状态"""
|
373
|
+
if not self.model:
|
374
|
+
return False # No model, cannot restore
|
375
|
+
session_file = os.path.join(os.getcwd(), ".jarvis", "saved_session.json")
|
376
|
+
if not os.path.exists(session_file):
|
377
|
+
return False
|
378
|
+
|
379
|
+
if self.model.restore(session_file):
|
380
|
+
try:
|
381
|
+
os.remove(session_file)
|
382
|
+
PrettyOutput.print("会话已恢复,并已删除会话文件。", OutputType.SUCCESS)
|
383
|
+
except OSError as e:
|
384
|
+
PrettyOutput.print(f"删除会话文件失败: {e}", OutputType.ERROR)
|
385
|
+
return True
|
386
|
+
return False
|
387
|
+
|
359
388
|
def get_tool_registry(self) -> Optional[Any]:
|
360
389
|
"""获取工具注册表实例"""
|
361
390
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
@@ -781,18 +810,14 @@ arguments:
|
|
781
810
|
|
782
811
|
if get_interrupt():
|
783
812
|
set_interrupt(False)
|
784
|
-
user_input = self.multiline_inputer(
|
785
|
-
f"模型交互期间被中断,请输入用户干预信息:"
|
786
|
-
)
|
813
|
+
user_input = self.multiline_inputer(f"模型交互期间被中断,请输入用户干预信息:")
|
787
814
|
if user_input:
|
788
815
|
# 如果有工具调用且用户确认继续,则将干预信息和工具执行结果拼接为prompt
|
789
816
|
if any(
|
790
817
|
handler.can_handle(current_response)
|
791
818
|
for handler in self.output_handler
|
792
819
|
):
|
793
|
-
if user_confirm(
|
794
|
-
"检测到有工具调用,是否继续处理工具调用?", True
|
795
|
-
):
|
820
|
+
if user_confirm("检测到有工具调用,是否继续处理工具调用?", True):
|
796
821
|
self.prompt = f"{user_input}\n\n{current_response}"
|
797
822
|
continue
|
798
823
|
self.prompt += f"{user_input}"
|
@@ -838,9 +863,7 @@ arguments:
|
|
838
863
|
if self.use_methodology:
|
839
864
|
if not upload_methodology(self.model, other_files=self.files):
|
840
865
|
if self.files:
|
841
|
-
PrettyOutput.print(
|
842
|
-
"文件上传失败,将忽略文件列表", OutputType.WARNING
|
843
|
-
)
|
866
|
+
PrettyOutput.print("文件上传失败,将忽略文件列表", OutputType.WARNING)
|
844
867
|
# 上传失败则回退到本地加载
|
845
868
|
msg = self.prompt
|
846
869
|
for handler in self.input_handler:
|
@@ -848,14 +871,14 @@ arguments:
|
|
848
871
|
self.prompt = f"{self.prompt}\n\n以下是历史类似问题的执行经验,可参考:\n{load_methodology(msg, self.get_tool_registry())}"
|
849
872
|
else:
|
850
873
|
if self.files:
|
851
|
-
self.prompt =
|
874
|
+
self.prompt = (
|
875
|
+
f"{self.prompt}\n\n上传的文件包含历史对话信息和方法论文件,可以从中获取一些经验信息。"
|
876
|
+
)
|
852
877
|
else:
|
853
878
|
self.prompt = f"{self.prompt}\n\n上传的文件包含历史对话信息,可以从中获取一些经验信息。"
|
854
879
|
elif self.files:
|
855
880
|
if not self.model.upload_files(self.files):
|
856
|
-
PrettyOutput.print(
|
857
|
-
"文件上传失败,将忽略文件列表", OutputType.WARNING
|
858
|
-
)
|
881
|
+
PrettyOutput.print("文件上传失败,将忽略文件列表", OutputType.WARNING)
|
859
882
|
else:
|
860
883
|
self.prompt = f"{self.prompt}\n\n上传的文件包含历史对话信息,可以从中获取一些经验信息。"
|
861
884
|
else:
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
import re
|
3
|
+
import sys
|
3
4
|
from typing import Any, Tuple
|
4
5
|
|
5
6
|
from jarvis.jarvis_utils.config import get_replace_map
|
@@ -29,7 +30,6 @@ def builtin_input_handler(user_input: str, agent_: Any) -> Tuple[str, bool]:
|
|
29
30
|
replace_map = get_replace_map()
|
30
31
|
# 处理每个标记
|
31
32
|
for tag in special_tags:
|
32
|
-
|
33
33
|
# 优先处理特殊标记
|
34
34
|
if tag == "Summary":
|
35
35
|
agent._summarize_and_clear_history()
|
@@ -51,6 +51,17 @@ def builtin_input_handler(user_input: str, agent_: Any) -> Tuple[str, bool]:
|
|
51
51
|
|
52
52
|
load_config()
|
53
53
|
return "", True
|
54
|
+
elif tag == "SaveSession":
|
55
|
+
if agent.save_session():
|
56
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
57
|
+
|
58
|
+
PrettyOutput.print("会话已成功保存。正在退出...", OutputType.SUCCESS)
|
59
|
+
sys.exit(0)
|
60
|
+
else:
|
61
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
62
|
+
|
63
|
+
PrettyOutput.print("保存会话失败。", OutputType.ERROR)
|
64
|
+
return "", True
|
54
65
|
|
55
66
|
processed_tag = set()
|
56
67
|
add_on_prompt = ""
|
@@ -206,48 +206,60 @@ class EditFileHandler(OutputHandler):
|
|
206
206
|
exact_search = search_text
|
207
207
|
|
208
208
|
if exact_search in modified_content:
|
209
|
-
if modified_content.count(exact_search) > 1:
|
210
|
-
PrettyOutput.print(
|
211
|
-
f"搜索文本在文件中存在多处匹配:\n{exact_search}",
|
212
|
-
output_type=OutputType.WARNING,
|
213
|
-
)
|
214
|
-
return False, f"搜索文本在文件中存在多处匹配:\n{exact_search}"
|
215
|
-
|
216
209
|
# 直接执行替换(保留所有原始格式)
|
217
210
|
modified_content = modified_content.replace(
|
218
211
|
exact_search, replace_text
|
219
212
|
)
|
220
213
|
print(f"✅ 补丁 #{patch_count} 应用成功")
|
221
214
|
else:
|
222
|
-
# 尝试增加缩进重试
|
223
215
|
found = False
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
)
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
if
|
234
|
-
if modified_content.count(indented_search) > 1:
|
235
|
-
PrettyOutput.print(
|
236
|
-
f"搜索文本在文件中存在多处匹配:\n{indented_search}",
|
237
|
-
output_type=OutputType.WARNING,
|
238
|
-
)
|
239
|
-
return (
|
240
|
-
False,
|
241
|
-
f"搜索文本在文件中存在多处匹配:\n{indented_search}",
|
242
|
-
)
|
216
|
+
# 如果匹配不到,并且search与replace块的首尾都是换行,尝试去掉第一个和最后一个换行
|
217
|
+
if (
|
218
|
+
search_text.startswith("\n")
|
219
|
+
and search_text.endswith("\n")
|
220
|
+
and replace_text.startswith("\n")
|
221
|
+
and replace_text.endswith("\n")
|
222
|
+
):
|
223
|
+
stripped_search = search_text[1:-1]
|
224
|
+
stripped_replace = replace_text[1:-1]
|
225
|
+
if stripped_search in modified_content:
|
243
226
|
modified_content = modified_content.replace(
|
244
|
-
|
245
|
-
)
|
246
|
-
print(
|
247
|
-
f"✅ 补丁 #{patch_count} 应用成功 (自动增加 {space_count} 个空格缩进)"
|
227
|
+
stripped_search, stripped_replace
|
248
228
|
)
|
229
|
+
print(f"✅ 补丁 #{patch_count} 应用成功 (自动去除首尾换行)")
|
249
230
|
found = True
|
250
|
-
|
231
|
+
|
232
|
+
if not found:
|
233
|
+
# 尝试增加缩进重试
|
234
|
+
current_search = search_text
|
235
|
+
current_replace = replace_text
|
236
|
+
if (
|
237
|
+
current_search.startswith("\n")
|
238
|
+
and current_search.endswith("\n")
|
239
|
+
and current_replace.startswith("\n")
|
240
|
+
and current_replace.endswith("\n")
|
241
|
+
):
|
242
|
+
current_search = current_search[1:-1]
|
243
|
+
current_replace = current_replace[1:-1]
|
244
|
+
|
245
|
+
for space_count in range(1, 17):
|
246
|
+
indented_search = "\n".join(
|
247
|
+
" " * space_count + line if line.strip() else line
|
248
|
+
for line in current_search.split("\n")
|
249
|
+
)
|
250
|
+
indented_replace = "\n".join(
|
251
|
+
" " * space_count + line if line.strip() else line
|
252
|
+
for line in current_replace.split("\n")
|
253
|
+
)
|
254
|
+
if indented_search in modified_content:
|
255
|
+
modified_content = modified_content.replace(
|
256
|
+
indented_search, indented_replace
|
257
|
+
)
|
258
|
+
print(
|
259
|
+
f"✅ 补丁 #{patch_count} 应用成功 (自动增加 {space_count} 个空格缩进)"
|
260
|
+
)
|
261
|
+
found = True
|
262
|
+
break
|
251
263
|
|
252
264
|
if not found:
|
253
265
|
PrettyOutput.print(
|
@@ -131,7 +131,7 @@ class CodeAgent:
|
|
131
131
|
input_handler=[shell_input_handler, builtin_input_handler],
|
132
132
|
need_summary=need_summary,
|
133
133
|
use_methodology=False, # 禁用方法论
|
134
|
-
use_analysis=False
|
134
|
+
use_analysis=False, # 禁用分析
|
135
135
|
)
|
136
136
|
|
137
137
|
self.agent.set_after_tool_call_cb(self.after_tool_call_cb)
|
@@ -359,9 +359,7 @@ class CodeAgent:
|
|
359
359
|
|
360
360
|
# 添加提交信息到final_ret
|
361
361
|
if commits:
|
362
|
-
final_ret +=
|
363
|
-
f"\n\n代码已修改完成\n补丁内容:\n```diff\n{diff}\n```\n"
|
364
|
-
)
|
362
|
+
final_ret += f"\n\n代码已修改完成\n补丁内容:\n```diff\n{diff}\n```\n"
|
365
363
|
# 修改后的提示逻辑
|
366
364
|
lint_tools_info = "\n".join(
|
367
365
|
f" - {file}: 使用 {'、'.join(get_lint_tools(file))}"
|
@@ -380,6 +378,7 @@ class CodeAgent:
|
|
380
378
|
{file_list}
|
381
379
|
{tool_info}
|
382
380
|
如果本次修改引入了警告和错误,请根据警告和错误信息修复代码
|
381
|
+
注意:如果要进行静态检查,需要在所有的修改都完成之后进行集中检查
|
383
382
|
"""
|
384
383
|
agent.set_addon_prompt(addon_prompt)
|
385
384
|
else:
|
@@ -428,6 +427,13 @@ def main() -> None:
|
|
428
427
|
|
429
428
|
try:
|
430
429
|
agent = CodeAgent(platform=args.platform, model=args.model, need_summary=False)
|
430
|
+
|
431
|
+
# 尝试恢复会话
|
432
|
+
if agent.agent.restore_session():
|
433
|
+
PrettyOutput.print(
|
434
|
+
"已从 .jarvis/saved_session.json 恢复会话。", OutputType.SUCCESS
|
435
|
+
)
|
436
|
+
|
431
437
|
if args.requirement:
|
432
438
|
agent.run(args.requirement)
|
433
439
|
else:
|
@@ -0,0 +1,309 @@
|
|
1
|
+
import os
|
2
|
+
from typing import Any, Dict, Generator, List, Tuple
|
3
|
+
|
4
|
+
from jarvis.jarvis_platform.base import BasePlatform
|
5
|
+
import json
|
6
|
+
|
7
|
+
from jarvis.jarvis_utils import http
|
8
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
9
|
+
from jarvis.jarvis_utils.utils import while_success
|
10
|
+
|
11
|
+
|
12
|
+
class AI8Model(BasePlatform):
|
13
|
+
"""AI8 model implementation"""
|
14
|
+
|
15
|
+
platform_name = "ai8"
|
16
|
+
BASE_URL = "https://ai8.rcouyi.com"
|
17
|
+
|
18
|
+
def get_model_list(self) -> List[Tuple[str, str]]:
|
19
|
+
"""获取模型列表"""
|
20
|
+
self.get_available_models()
|
21
|
+
return [(name, info["desc"]) for name, info in self.models.items()]
|
22
|
+
|
23
|
+
def __init__(self):
|
24
|
+
"""Initialize model"""
|
25
|
+
super().__init__()
|
26
|
+
self.system_prompt = ""
|
27
|
+
self.conversation = {}
|
28
|
+
self.models = {} # 存储模型信息
|
29
|
+
|
30
|
+
self.token = os.getenv("AI8_API_KEY")
|
31
|
+
if not self.token:
|
32
|
+
PrettyOutput.print("未设置 AI8_API_KEY", OutputType.WARNING)
|
33
|
+
|
34
|
+
self.headers = {
|
35
|
+
"Authorization": self.token,
|
36
|
+
"Content-Type": "application/json",
|
37
|
+
"Accept": "application/json, text/plain, */*",
|
38
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
39
|
+
"X-APP-VERSION": "2.3.0",
|
40
|
+
"Origin": self.BASE_URL,
|
41
|
+
"Referer": f"{self.BASE_URL}/chat?_userMenuKey=chat",
|
42
|
+
"Sec-Fetch-Site": "same-origin",
|
43
|
+
"Sec-Fetch-Mode": "cors",
|
44
|
+
"Sec-Fetch-Dest": "empty",
|
45
|
+
}
|
46
|
+
|
47
|
+
self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
|
48
|
+
if self.model_name not in self.get_available_models():
|
49
|
+
PrettyOutput.print(
|
50
|
+
f"警告: 选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING
|
51
|
+
)
|
52
|
+
|
53
|
+
def set_model_name(self, model_name: str):
|
54
|
+
"""Set model name"""
|
55
|
+
|
56
|
+
self.model_name = model_name
|
57
|
+
|
58
|
+
def create_conversation(self) -> bool:
|
59
|
+
"""Create a new conversation"""
|
60
|
+
try:
|
61
|
+
# 1. 创建会话
|
62
|
+
response = while_success(
|
63
|
+
lambda: http.post(
|
64
|
+
f"{self.BASE_URL}/api/chat/session", headers=self.headers, json={}
|
65
|
+
),
|
66
|
+
sleep_time=5,
|
67
|
+
)
|
68
|
+
|
69
|
+
data = response.json()
|
70
|
+
if data["code"] != 0:
|
71
|
+
PrettyOutput.print(
|
72
|
+
f"创建会话失败: {data.get('msg', '未知错误')}", OutputType.WARNING
|
73
|
+
)
|
74
|
+
return False
|
75
|
+
|
76
|
+
self.conversation = data["data"]
|
77
|
+
|
78
|
+
# 2. 更新会话设置
|
79
|
+
session_data = {
|
80
|
+
**self.conversation,
|
81
|
+
"model": self.model_name,
|
82
|
+
"contextCount": 65536,
|
83
|
+
"prompt": self.system_prompt,
|
84
|
+
"plugins": [],
|
85
|
+
"localPlugins": None,
|
86
|
+
"useAppId": 0,
|
87
|
+
}
|
88
|
+
|
89
|
+
response = while_success(
|
90
|
+
lambda: http.put(
|
91
|
+
f"{self.BASE_URL}/api/chat/session/{self.conversation['id']}", # type: ignore
|
92
|
+
headers=self.headers,
|
93
|
+
json=session_data,
|
94
|
+
),
|
95
|
+
sleep_time=5,
|
96
|
+
)
|
97
|
+
|
98
|
+
data = response.json()
|
99
|
+
if data["code"] == 0:
|
100
|
+
self.conversation = data["data"]
|
101
|
+
return True
|
102
|
+
else:
|
103
|
+
PrettyOutput.print(
|
104
|
+
f"更新会话设置失败: {data.get('msg', '未知错误')}",
|
105
|
+
OutputType.WARNING,
|
106
|
+
)
|
107
|
+
return False
|
108
|
+
|
109
|
+
except Exception as e:
|
110
|
+
PrettyOutput.print(f"创建会话失败: {str(e)}", OutputType.ERROR)
|
111
|
+
return False
|
112
|
+
|
113
|
+
def set_system_prompt(self, message: str):
|
114
|
+
"""Set system message"""
|
115
|
+
self.system_prompt = message
|
116
|
+
|
117
|
+
def chat(self, message: str) -> Generator[str, None, None]:
|
118
|
+
"""Execute conversation"""
|
119
|
+
try:
|
120
|
+
# 确保有会话ID
|
121
|
+
if not self.conversation:
|
122
|
+
if not self.create_conversation():
|
123
|
+
raise Exception("Failed to create conversation")
|
124
|
+
|
125
|
+
payload: Dict[str, Any] = {
|
126
|
+
"text": message,
|
127
|
+
"sessionId": self.conversation["id"] if self.conversation else None,
|
128
|
+
"files": [],
|
129
|
+
}
|
130
|
+
|
131
|
+
# 使用stream_post进行流式请求
|
132
|
+
response_stream = while_success(
|
133
|
+
lambda: http.stream_post(
|
134
|
+
f"{self.BASE_URL}/api/chat/completions",
|
135
|
+
headers=self.headers,
|
136
|
+
json=payload,
|
137
|
+
),
|
138
|
+
sleep_time=5,
|
139
|
+
)
|
140
|
+
|
141
|
+
# 处理流式响应
|
142
|
+
for chunk in response_stream:
|
143
|
+
if chunk:
|
144
|
+
try:
|
145
|
+
line = chunk.decode("utf-8")
|
146
|
+
if line.startswith("data: "):
|
147
|
+
try:
|
148
|
+
data = json.loads(line[6:])
|
149
|
+
if data.get("type") == "string":
|
150
|
+
chunk_data = data.get("data", "")
|
151
|
+
if chunk_data:
|
152
|
+
yield chunk_data
|
153
|
+
|
154
|
+
except json.JSONDecodeError:
|
155
|
+
continue
|
156
|
+
|
157
|
+
except UnicodeDecodeError:
|
158
|
+
continue
|
159
|
+
|
160
|
+
return None
|
161
|
+
|
162
|
+
except Exception as e:
|
163
|
+
PrettyOutput.print(f"对话异常: {str(e)}", OutputType.ERROR)
|
164
|
+
raise e
|
165
|
+
|
166
|
+
def name(self) -> str:
|
167
|
+
"""Return model name"""
|
168
|
+
return self.model_name
|
169
|
+
|
170
|
+
def delete_chat(self) -> bool:
|
171
|
+
"""Delete current chat session"""
|
172
|
+
try:
|
173
|
+
if not self.conversation:
|
174
|
+
return True
|
175
|
+
|
176
|
+
response = while_success(
|
177
|
+
lambda: http.delete(
|
178
|
+
f"{self.BASE_URL}/api/chat/session/{self.conversation['id']}", # type: ignore
|
179
|
+
headers=self.headers,
|
180
|
+
),
|
181
|
+
sleep_time=5,
|
182
|
+
)
|
183
|
+
|
184
|
+
data = response.json()
|
185
|
+
if data["code"] == 0:
|
186
|
+
self.conversation = {}
|
187
|
+
return True
|
188
|
+
else:
|
189
|
+
error_msg = f"删除会话失败: {data.get('msg', '未知错误')}"
|
190
|
+
PrettyOutput.print(error_msg, OutputType.WARNING)
|
191
|
+
return False
|
192
|
+
|
193
|
+
except Exception as e:
|
194
|
+
PrettyOutput.print(f"删除会话失败: {str(e)}", OutputType.ERROR)
|
195
|
+
return False
|
196
|
+
|
197
|
+
def save(self, file_path: str) -> bool:
|
198
|
+
"""Save chat session to a file."""
|
199
|
+
if not self.conversation:
|
200
|
+
PrettyOutput.print("没有活动的会话可供保存", OutputType.WARNING)
|
201
|
+
return False
|
202
|
+
|
203
|
+
state = {
|
204
|
+
"conversation": self.conversation,
|
205
|
+
"model_name": self.model_name,
|
206
|
+
"system_prompt": self.system_prompt,
|
207
|
+
}
|
208
|
+
|
209
|
+
try:
|
210
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
211
|
+
json.dump(state, f, ensure_ascii=False, indent=4)
|
212
|
+
self._saved = True
|
213
|
+
PrettyOutput.print(f"会话已成功保存到 {file_path}", OutputType.SUCCESS)
|
214
|
+
return True
|
215
|
+
except Exception as e:
|
216
|
+
PrettyOutput.print(f"保存会话失败: {str(e)}", OutputType.ERROR)
|
217
|
+
return False
|
218
|
+
|
219
|
+
def restore(self, file_path: str) -> bool:
|
220
|
+
"""Restore chat session from a file."""
|
221
|
+
try:
|
222
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
223
|
+
state = json.load(f)
|
224
|
+
|
225
|
+
self.conversation = state["conversation"]
|
226
|
+
self.model_name = state["model_name"]
|
227
|
+
self.system_prompt = state.get("system_prompt", "")
|
228
|
+
|
229
|
+
# A restored session should not be deleted on exit, as it's persistent.
|
230
|
+
self._saved = True
|
231
|
+
|
232
|
+
PrettyOutput.print(f"从 {file_path} 成功恢复会话", OutputType.SUCCESS)
|
233
|
+
return True
|
234
|
+
except FileNotFoundError:
|
235
|
+
PrettyOutput.print(f"会话文件未找到: {file_path}", OutputType.ERROR)
|
236
|
+
return False
|
237
|
+
except KeyError as e:
|
238
|
+
PrettyOutput.print(f"恢复失败: 会话文件格式不正确,缺少键 {e}", OutputType.ERROR)
|
239
|
+
return False
|
240
|
+
except Exception as e:
|
241
|
+
PrettyOutput.print(f"恢复会话失败: {str(e)}", OutputType.ERROR)
|
242
|
+
return False
|
243
|
+
|
244
|
+
def get_available_models(self) -> List[str]:
|
245
|
+
"""Get available model list
|
246
|
+
|
247
|
+
Returns:
|
248
|
+
List[str]: Available model name list
|
249
|
+
"""
|
250
|
+
try:
|
251
|
+
if self.models:
|
252
|
+
return list(self.models.keys())
|
253
|
+
|
254
|
+
response = while_success(
|
255
|
+
lambda: http.get(
|
256
|
+
f"{self.BASE_URL}/api/chat/tmpl", headers=self.headers
|
257
|
+
),
|
258
|
+
sleep_time=5,
|
259
|
+
)
|
260
|
+
|
261
|
+
data = response.json()
|
262
|
+
if data["code"] != 0:
|
263
|
+
PrettyOutput.print(
|
264
|
+
f"获取模型列表失败: {data.get('msg', '未知错误')}",
|
265
|
+
OutputType.WARNING,
|
266
|
+
)
|
267
|
+
return []
|
268
|
+
|
269
|
+
# 保存模型信息
|
270
|
+
self.models = {model["value"]: model for model in data["data"]["models"]}
|
271
|
+
|
272
|
+
for model in self.models.values():
|
273
|
+
# 添加标签
|
274
|
+
model_str = f"{model['label']}"
|
275
|
+
|
276
|
+
# 添加特性标记
|
277
|
+
features = []
|
278
|
+
if model["attr"].get("multimodal"):
|
279
|
+
features.append("Multimodal")
|
280
|
+
if model["attr"].get("plugin"):
|
281
|
+
features.append("Plugin support")
|
282
|
+
if model["attr"].get("onlyImg"):
|
283
|
+
features.append("Image support")
|
284
|
+
if model["attr"].get("tag"):
|
285
|
+
features.append(model["attr"]["tag"])
|
286
|
+
if model["attr"].get("integral"):
|
287
|
+
features.append(model["attr"]["integral"])
|
288
|
+
# 添加备注
|
289
|
+
if model["attr"].get("note"):
|
290
|
+
model_str += f" - {model['attr']['note']}"
|
291
|
+
if features:
|
292
|
+
model_str += f" [{'|'.join(features)}]"
|
293
|
+
|
294
|
+
model["desc"] = model_str
|
295
|
+
|
296
|
+
return list(self.models.keys())
|
297
|
+
|
298
|
+
except Exception as e:
|
299
|
+
PrettyOutput.print(f"获取模型列表失败: {str(e)}", OutputType.ERROR)
|
300
|
+
return []
|
301
|
+
|
302
|
+
def support_upload_files(self) -> bool:
|
303
|
+
return False
|
304
|
+
|
305
|
+
def support_web(self) -> bool:
|
306
|
+
return False
|
307
|
+
|
308
|
+
def upload_files(self, file_list: List[str]) -> bool:
|
309
|
+
return False
|