jarvis-ai-assistant 0.2.1__py3-none-any.whl → 0.2.3__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/jarvis.py +61 -59
- jarvis/jarvis_agent/main.py +42 -40
- jarvis/jarvis_agent/prompts.py +26 -4
- jarvis/jarvis_code_agent/code_agent.py +35 -31
- jarvis/jarvis_code_analysis/code_review.py +73 -39
- jarvis/jarvis_data/config_schema.json +67 -12
- jarvis/jarvis_git_squash/main.py +16 -12
- jarvis/jarvis_git_utils/git_commiter.py +25 -20
- jarvis/jarvis_methodology/main.py +34 -49
- jarvis/jarvis_multi_agent/main.py +28 -23
- jarvis/jarvis_platform/ai8.py +31 -22
- jarvis/jarvis_platform/kimi.py +31 -61
- jarvis/jarvis_platform/tongyi.py +71 -85
- jarvis/jarvis_platform/yuanbao.py +44 -50
- jarvis/jarvis_platform_manager/main.py +55 -90
- jarvis/jarvis_rag/cli.py +79 -23
- jarvis/jarvis_rag/query_rewriter.py +61 -12
- jarvis/jarvis_rag/rag_pipeline.py +143 -34
- jarvis/jarvis_rag/retriever.py +5 -5
- jarvis/jarvis_smart_shell/main.py +58 -87
- jarvis/jarvis_tools/cli/main.py +120 -153
- jarvis/jarvis_tools/generate_new_tool.py +22 -1
- jarvis/jarvis_tools/registry.py +1 -7
- jarvis/jarvis_tools/search_web.py +12 -10
- jarvis/jarvis_utils/config.py +92 -11
- jarvis/jarvis_utils/globals.py +29 -8
- jarvis/jarvis_utils/http.py +58 -79
- jarvis/jarvis_utils/input.py +114 -121
- jarvis/jarvis_utils/output.py +1 -1
- jarvis/jarvis_utils/utils.py +3 -0
- jarvis_ai_assistant-0.2.3.dist-info/METADATA +301 -0
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/RECORD +37 -40
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/entry_points.txt +0 -2
- jarvis/jarvis_git_details/__init__.py +0 -0
- jarvis/jarvis_git_details/main.py +0 -265
- jarvis/jarvis_platform/oyi.py +0 -357
- jarvis_ai_assistant-0.2.1.dist-info/METADATA +0 -845
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.3.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
jarvis/jarvis_agent/jarvis.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
import argparse
|
3
2
|
import os
|
4
3
|
import shutil
|
5
4
|
import subprocess
|
@@ -7,6 +6,7 @@ import sys
|
|
7
6
|
from pathlib import Path
|
8
7
|
from typing import Dict, Optional
|
9
8
|
|
9
|
+
import typer
|
10
10
|
import yaml # type: ignore
|
11
11
|
from prompt_toolkit import prompt # type: ignore
|
12
12
|
|
@@ -24,6 +24,8 @@ from jarvis.jarvis_tools.registry import ToolRegistry
|
|
24
24
|
from jarvis.jarvis_utils.config import get_data_dir
|
25
25
|
from jarvis.jarvis_utils.utils import init_env
|
26
26
|
|
27
|
+
app = typer.Typer(help="Jarvis AI assistant")
|
28
|
+
|
27
29
|
|
28
30
|
def _load_tasks() -> Dict[str, str]:
|
29
31
|
"""Load tasks from .jarvis files in user home and current directory."""
|
@@ -109,48 +111,14 @@ def _select_task(tasks: Dict[str, str]) -> str:
|
|
109
111
|
PrettyOutput.print(f"选择任务失败: {str(val_err)}", OutputType.ERROR)
|
110
112
|
|
111
113
|
|
112
|
-
def
|
113
|
-
"""Parse command line arguments."""
|
114
|
-
parser = argparse.ArgumentParser(description="Jarvis AI assistant")
|
115
|
-
parser.add_argument(
|
116
|
-
"--llm_type",
|
117
|
-
type=str,
|
118
|
-
default="normal",
|
119
|
-
choices=["normal", "thinking"],
|
120
|
-
help="LLM type to use",
|
121
|
-
)
|
122
|
-
parser.add_argument(
|
123
|
-
"-t",
|
124
|
-
"--task",
|
125
|
-
type=str,
|
126
|
-
help="Directly input task content from command line",
|
127
|
-
)
|
128
|
-
parser.add_argument(
|
129
|
-
"--model_group",
|
130
|
-
type=str,
|
131
|
-
help="Model group to use, overriding config",
|
132
|
-
)
|
133
|
-
parser.add_argument("-f", "--config", type=str, help="Path to custom config file")
|
134
|
-
parser.add_argument(
|
135
|
-
"--restore-session",
|
136
|
-
action="store_true",
|
137
|
-
help="Restore session from .jarvis/saved_session.json",
|
138
|
-
default=False,
|
139
|
-
)
|
140
|
-
parser.add_argument(
|
141
|
-
"-e", "--edit", action="store_true", help="Edit the configuration file"
|
142
|
-
)
|
143
|
-
return parser.parse_args()
|
144
|
-
|
145
|
-
|
146
|
-
def _handle_edit_mode(args: argparse.Namespace) -> None:
|
114
|
+
def _handle_edit_mode(edit: bool, config_file: Optional[str]) -> None:
|
147
115
|
"""If edit flag is set, open config file in editor and exit."""
|
148
|
-
if not
|
116
|
+
if not edit:
|
149
117
|
return
|
150
118
|
|
151
119
|
config_file_path = (
|
152
|
-
Path(
|
153
|
-
if
|
120
|
+
Path(config_file)
|
121
|
+
if config_file
|
154
122
|
else Path(os.path.expanduser("~/.jarvis/config.yaml"))
|
155
123
|
)
|
156
124
|
editors = ["nvim", "vim", "vi"]
|
@@ -159,30 +127,32 @@ def _handle_edit_mode(args: argparse.Namespace) -> None:
|
|
159
127
|
if editor:
|
160
128
|
try:
|
161
129
|
subprocess.run([editor, str(config_file_path)], check=True)
|
162
|
-
|
130
|
+
raise typer.Exit(code=0)
|
163
131
|
except (subprocess.CalledProcessError, FileNotFoundError) as e:
|
164
132
|
PrettyOutput.print(f"Failed to open editor: {e}", OutputType.ERROR)
|
165
|
-
|
133
|
+
raise typer.Exit(code=1)
|
166
134
|
else:
|
167
135
|
PrettyOutput.print(
|
168
136
|
"No suitable editor found (nvim, vim, vi).", OutputType.ERROR
|
169
137
|
)
|
170
|
-
|
138
|
+
raise typer.Exit(code=1)
|
171
139
|
|
172
140
|
|
173
|
-
def _initialize_agent(
|
141
|
+
def _initialize_agent(
|
142
|
+
llm_type: str, model_group: Optional[str], restore_session: bool
|
143
|
+
) -> Agent:
|
174
144
|
"""Initialize the agent and restore session if requested."""
|
175
145
|
agent = Agent(
|
176
146
|
system_prompt=origin_agent_system_prompt,
|
177
|
-
llm_type=
|
178
|
-
model_group=
|
147
|
+
llm_type=llm_type,
|
148
|
+
model_group=model_group,
|
179
149
|
input_handler=[shell_input_handler, builtin_input_handler],
|
180
150
|
output_handler=[ToolRegistry()], # type: ignore
|
181
151
|
need_summary=False,
|
182
152
|
)
|
183
153
|
|
184
154
|
# 尝试恢复会话
|
185
|
-
if
|
155
|
+
if restore_session:
|
186
156
|
if agent.restore_session():
|
187
157
|
PrettyOutput.print("会话已成功恢复。", OutputType.SUCCESS)
|
188
158
|
else:
|
@@ -195,36 +165,68 @@ def _get_and_run_task(agent: Agent, task_content: Optional[str] = None) -> None:
|
|
195
165
|
# 优先处理命令行直接传入的任务
|
196
166
|
if task_content:
|
197
167
|
agent.run(task_content)
|
198
|
-
|
168
|
+
raise typer.Exit(code=0)
|
199
169
|
|
200
170
|
if agent.first:
|
201
171
|
tasks = _load_tasks()
|
202
172
|
if tasks and (selected_task := _select_task(tasks)):
|
203
173
|
PrettyOutput.print(f"开始执行任务: \n{selected_task}", OutputType.INFO)
|
204
174
|
agent.run(selected_task)
|
205
|
-
|
175
|
+
raise typer.Exit(code=0)
|
206
176
|
|
207
177
|
user_input = get_multiline_input("请输入你的任务(输入空行退出):")
|
208
178
|
if user_input:
|
209
179
|
agent.run(user_input)
|
210
|
-
|
180
|
+
raise typer.Exit(code=0)
|
211
181
|
|
212
182
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
183
|
+
@app.callback(invoke_without_command=True)
|
184
|
+
def run_cli(
|
185
|
+
ctx: typer.Context,
|
186
|
+
llm_type: str = typer.Option(
|
187
|
+
"normal",
|
188
|
+
"--llm_type",
|
189
|
+
help="LLM type to use, choices are 'normal' and 'thinking'",
|
190
|
+
),
|
191
|
+
task: Optional[str] = typer.Option(
|
192
|
+
None, "-t", "--task", help="Directly input task content from command line"
|
193
|
+
),
|
194
|
+
model_group: Optional[str] = typer.Option(
|
195
|
+
None, "--model_group", help="Model group to use, overriding config"
|
196
|
+
),
|
197
|
+
config_file: Optional[str] = typer.Option(
|
198
|
+
None, "-f", "--config", help="Path to custom config file"
|
199
|
+
),
|
200
|
+
restore_session: bool = typer.Option(
|
201
|
+
False,
|
202
|
+
"--restore-session",
|
203
|
+
help="Restore session from .jarvis/saved_session.json",
|
204
|
+
),
|
205
|
+
edit: bool = typer.Option(
|
206
|
+
False, "-e", "--edit", help="Edit the configuration file"
|
207
|
+
),
|
208
|
+
) -> None:
|
209
|
+
"""Jarvis AI assistant command-line interface."""
|
210
|
+
if ctx.invoked_subcommand is not None:
|
211
|
+
return
|
212
|
+
|
213
|
+
_handle_edit_mode(edit, config_file)
|
217
214
|
|
218
|
-
init_env(
|
219
|
-
"欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!", config_file=args.config
|
220
|
-
)
|
215
|
+
init_env("欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!", config_file=config_file)
|
221
216
|
|
222
217
|
try:
|
223
|
-
agent = _initialize_agent(
|
224
|
-
_get_and_run_task(agent,
|
218
|
+
agent = _initialize_agent(llm_type, model_group, restore_session)
|
219
|
+
_get_and_run_task(agent, task)
|
220
|
+
except typer.Exit:
|
221
|
+
raise
|
225
222
|
except Exception as err: # pylint: disable=broad-except
|
226
223
|
PrettyOutput.print(f"初始化错误: {str(err)}", OutputType.ERROR)
|
227
|
-
|
224
|
+
raise typer.Exit(code=1)
|
225
|
+
|
226
|
+
|
227
|
+
def main() -> None:
|
228
|
+
"""Application entry point."""
|
229
|
+
app()
|
228
230
|
|
229
231
|
|
230
232
|
if __name__ == "__main__":
|
jarvis/jarvis_agent/main.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
import argparse
|
3
2
|
import os
|
3
|
+
from typing import Optional
|
4
4
|
|
5
|
+
import typer
|
5
6
|
import yaml
|
6
7
|
|
7
8
|
from jarvis.jarvis_agent import Agent
|
@@ -9,6 +10,8 @@ from jarvis.jarvis_utils.input import get_multiline_input
|
|
9
10
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
10
11
|
from jarvis.jarvis_utils.utils import init_env
|
11
12
|
|
13
|
+
app = typer.Typer(help="Jarvis AI assistant")
|
14
|
+
|
12
15
|
|
13
16
|
def load_config(config_path: str) -> dict:
|
14
17
|
"""从YAML文件加载配置
|
@@ -34,59 +37,53 @@ def load_config(config_path: str) -> dict:
|
|
34
37
|
return {}
|
35
38
|
|
36
39
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
40
|
+
@app.command()
|
41
|
+
def cli(
|
42
|
+
config_file: Optional[str] = typer.Option(
|
43
|
+
None, "-f", "--config", help="Path to agent config file"
|
44
|
+
),
|
45
|
+
agent_definition: Optional[str] = typer.Option(
|
46
|
+
None, "-c", "--agent_definition", help="Path to agent definition file"
|
47
|
+
),
|
48
|
+
task: Optional[str] = typer.Option(
|
49
|
+
None, "-t", "--task", help="Initial task to execute"
|
50
|
+
),
|
51
|
+
llm_type: str = typer.Option(
|
52
|
+
"normal",
|
49
53
|
"--llm_type",
|
50
|
-
type=str,
|
51
|
-
default="normal",
|
52
|
-
choices=["normal", "thinking"],
|
53
54
|
help="LLM type to use, overriding config",
|
54
|
-
)
|
55
|
-
|
56
|
-
"--model_group",
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
args = parser.parse_args()
|
61
|
-
|
55
|
+
),
|
56
|
+
model_group: Optional[str] = typer.Option(
|
57
|
+
None, "--model_group", help="Model group to use, overriding config"
|
58
|
+
),
|
59
|
+
):
|
60
|
+
"""Main entry point for Jarvis agent"""
|
62
61
|
# Initialize environment
|
63
|
-
init_env(
|
64
|
-
"欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!", config_file=args.config
|
65
|
-
)
|
62
|
+
init_env("欢迎使用 Jarvis AI 助手,您的智能助理已准备就绪!", config_file=config_file)
|
66
63
|
|
67
64
|
# Load configuration
|
68
|
-
config = load_config(
|
65
|
+
config = load_config(agent_definition) if agent_definition else {}
|
69
66
|
|
70
67
|
# Override config with command-line arguments if provided
|
71
|
-
if
|
72
|
-
config["llm_type"] =
|
73
|
-
if
|
74
|
-
config["model_group"] =
|
68
|
+
if llm_type:
|
69
|
+
config["llm_type"] = llm_type
|
70
|
+
if model_group:
|
71
|
+
config["model_group"] = model_group
|
75
72
|
|
76
73
|
# Create and run agent
|
77
74
|
try:
|
78
75
|
agent = Agent(**config)
|
79
76
|
|
80
77
|
# Run agent with initial task if specified
|
81
|
-
if
|
82
|
-
PrettyOutput.print(f"执行初始任务: {
|
83
|
-
agent.run(
|
84
|
-
|
78
|
+
if task:
|
79
|
+
PrettyOutput.print(f"执行初始任务: {task}", OutputType.INFO)
|
80
|
+
agent.run(task)
|
81
|
+
raise typer.Exit(code=0)
|
85
82
|
|
86
83
|
try:
|
87
84
|
user_input = get_multiline_input("请输入你的任务(输入空行退出):")
|
88
85
|
if not user_input:
|
89
|
-
|
86
|
+
raise typer.Exit(code=0)
|
90
87
|
agent.set_addon_prompt(
|
91
88
|
"如果有必要,请先指定出行动计划,然后根据计划一步步执行,如果任务过于复杂,可以拆分子Agent进行执行,拆的子Agent需要掌握所有必要的任务信息,否则无法执行"
|
92
89
|
)
|
@@ -94,12 +91,17 @@ def main():
|
|
94
91
|
except Exception as e:
|
95
92
|
PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
|
96
93
|
|
94
|
+
except typer.Exit:
|
95
|
+
raise
|
97
96
|
except Exception as e:
|
98
97
|
PrettyOutput.print(f"初始化错误: {str(e)}", OutputType.ERROR)
|
99
|
-
|
98
|
+
raise typer.Exit(code=1)
|
99
|
+
|
100
100
|
|
101
|
-
|
101
|
+
def main() -> None:
|
102
|
+
"""Application entry point."""
|
103
|
+
app()
|
102
104
|
|
103
105
|
|
104
106
|
if __name__ == "__main__":
|
105
|
-
|
107
|
+
main()
|
jarvis/jarvis_agent/prompts.py
CHANGED
@@ -113,6 +113,31 @@ TASK_ANALYSIS_PROMPT = f"""<task_analysis>
|
|
113
113
|
"stderr": f"操作失败: {{str(e)}}"
|
114
114
|
}}
|
115
115
|
```
|
116
|
+
4. **在工具中调用大模型**:如果工具需要调用大模型来完成子任务(例如,生成代码、分析文本等),为了避免干扰主对话流程,建议创建一个独立的大模型实例。
|
117
|
+
```python
|
118
|
+
# 通过 agent 实例获取模型配置
|
119
|
+
agent = args.get("agent")
|
120
|
+
if not agent:
|
121
|
+
return {{"success": False, "stderr": "Agent not found."}}
|
122
|
+
|
123
|
+
current_model = agent.model
|
124
|
+
platform_name = current_model.platform_name()
|
125
|
+
model_name = current_model.name()
|
126
|
+
|
127
|
+
# 创建独立的模型实例
|
128
|
+
from jarvis.jarvis_platform.registry import PlatformRegistry
|
129
|
+
llm = PlatformRegistry().create_platform(platform_name)
|
130
|
+
if not llm:
|
131
|
+
return {{"success": False, "stderr": f"Platform {{platform_name}} not found."}}
|
132
|
+
|
133
|
+
llm.set_model_name(model_name)
|
134
|
+
llm.set_suppress_output(True) # 工具内的调用通常不需要流式输出
|
135
|
+
|
136
|
+
# 使用新实例调用大模型
|
137
|
+
PrettyOutput.print("正在执行子任务...", OutputType.INFO)
|
138
|
+
response = llm.chat_until_success("你的提示词")
|
139
|
+
PrettyOutput.print("子任务完成", OutputType.SUCCESS)
|
140
|
+
```
|
116
141
|
</tool_requirements>
|
117
142
|
<methodology_requirements>
|
118
143
|
方法论格式要求:
|
@@ -139,10 +164,7 @@ arguments:
|
|
139
164
|
from jarvis.jarvis_utils.output import PrettyOutput, OutputType
|
140
165
|
class 工具名称:
|
141
166
|
name = "工具名称"
|
142
|
-
description = "Tool
|
143
|
-
Tool description
|
144
|
-
适用场景:1. 格式化文本; 2. 处理标题; 3. 标准化输出
|
145
|
-
\"\"\"
|
167
|
+
description = "Tool description"
|
146
168
|
parameters = {{
|
147
169
|
"type": "object",
|
148
170
|
"properties": {{
|
@@ -4,12 +4,13 @@
|
|
4
4
|
该模块提供CodeAgent类,用于处理代码修改任务。
|
5
5
|
"""
|
6
6
|
|
7
|
-
import argparse
|
8
7
|
import os
|
9
8
|
import subprocess
|
10
9
|
import sys
|
11
10
|
from typing import List, Optional, Tuple
|
12
11
|
|
12
|
+
import typer
|
13
|
+
|
13
14
|
from jarvis.jarvis_agent import Agent
|
14
15
|
from jarvis.jarvis_agent.builtin_input_handler import builtin_input_handler
|
15
16
|
from jarvis.jarvis_agent.edit_file_handler import EditFileHandler
|
@@ -37,6 +38,8 @@ from jarvis.jarvis_utils.input import get_multiline_input, user_confirm
|
|
37
38
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
38
39
|
from jarvis.jarvis_utils.utils import get_loc_stats, init_env
|
39
40
|
|
41
|
+
app = typer.Typer(help="Jarvis Code Agent")
|
42
|
+
|
40
43
|
|
41
44
|
class CodeAgent:
|
42
45
|
"""Jarvis系统的代码修改代理。
|
@@ -401,33 +404,27 @@ class CodeAgent:
|
|
401
404
|
agent.session.prompt += final_ret
|
402
405
|
|
403
406
|
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
parser = argparse.ArgumentParser(description="Jarvis Code Agent")
|
409
|
-
parser.add_argument(
|
407
|
+
@app.command()
|
408
|
+
def cli(
|
409
|
+
llm_type: str = typer.Option(
|
410
|
+
"normal",
|
410
411
|
"--llm_type",
|
411
|
-
type
|
412
|
-
|
413
|
-
|
414
|
-
help="
|
415
|
-
)
|
416
|
-
|
417
|
-
"--
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
parser.add_argument(
|
422
|
-
"-r", "--requirement", type=str, help="Requirement to process", default=None
|
423
|
-
)
|
424
|
-
parser.add_argument(
|
412
|
+
help="LLM type to use, choices are 'normal' and 'thinking'",
|
413
|
+
),
|
414
|
+
model_group: Optional[str] = typer.Option(
|
415
|
+
None, "--model_group", help="Model group to use, overriding config"
|
416
|
+
),
|
417
|
+
requirement: Optional[str] = typer.Option(
|
418
|
+
None, "-r", "--requirement", help="Requirement to process"
|
419
|
+
),
|
420
|
+
restore_session: bool = typer.Option(
|
421
|
+
False,
|
425
422
|
"--restore-session",
|
426
|
-
action="store_true",
|
427
423
|
help="Restore session from .jarvis/saved_session.json",
|
428
|
-
|
429
|
-
|
430
|
-
|
424
|
+
),
|
425
|
+
) -> None:
|
426
|
+
"""Jarvis主入口点。"""
|
427
|
+
init_env("欢迎使用 Jarvis-CodeAgent,您的代码工程助手已准备就绪!")
|
431
428
|
|
432
429
|
curr_dir = os.getcwd()
|
433
430
|
git_dir = find_git_root_and_cd(curr_dir)
|
@@ -435,13 +432,13 @@ def main() -> None:
|
|
435
432
|
|
436
433
|
try:
|
437
434
|
agent = CodeAgent(
|
438
|
-
llm_type=
|
439
|
-
model_group=
|
435
|
+
llm_type=llm_type,
|
436
|
+
model_group=model_group,
|
440
437
|
need_summary=False,
|
441
438
|
)
|
442
439
|
|
443
440
|
# 尝试恢复会话
|
444
|
-
if
|
441
|
+
if restore_session:
|
445
442
|
if agent.agent.restore_session():
|
446
443
|
PrettyOutput.print(
|
447
444
|
"已从 .jarvis/saved_session.json 恢复会话。", OutputType.SUCCESS
|
@@ -451,19 +448,26 @@ def main() -> None:
|
|
451
448
|
"无法从 .jarvis/saved_session.json 恢复会话。", OutputType.WARNING
|
452
449
|
)
|
453
450
|
|
454
|
-
if
|
455
|
-
agent.run(
|
451
|
+
if requirement:
|
452
|
+
agent.run(requirement)
|
456
453
|
else:
|
457
454
|
while True:
|
458
455
|
user_input = get_multiline_input("请输入你的需求(输入空行退出):")
|
459
456
|
if not user_input:
|
460
|
-
|
457
|
+
raise typer.Exit(code=0)
|
461
458
|
agent.run(user_input)
|
462
459
|
|
460
|
+
except typer.Exit:
|
461
|
+
raise
|
463
462
|
except RuntimeError as e:
|
464
463
|
PrettyOutput.print(f"错误: {str(e)}", OutputType.ERROR)
|
465
464
|
sys.exit(1)
|
466
465
|
|
467
466
|
|
467
|
+
def main() -> None:
|
468
|
+
"""Application entry point."""
|
469
|
+
app()
|
470
|
+
|
471
|
+
|
468
472
|
if __name__ == "__main__":
|
469
473
|
main()
|
@@ -3,8 +3,11 @@ import os
|
|
3
3
|
import re
|
4
4
|
import subprocess
|
5
5
|
import tempfile
|
6
|
+
import sys
|
6
7
|
from typing import Any, Dict, List, Optional
|
7
8
|
|
9
|
+
import typer
|
10
|
+
|
8
11
|
from jarvis.jarvis_agent import Agent
|
9
12
|
from jarvis.jarvis_code_analysis.checklists.loader import get_language_checklist
|
10
13
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
@@ -14,6 +17,8 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
14
17
|
from jarvis.jarvis_utils.tag import ct, ot
|
15
18
|
from jarvis.jarvis_utils.utils import init_env, is_context_overflow
|
16
19
|
|
20
|
+
app = typer.Typer(help="Autonomous code review tool")
|
21
|
+
|
17
22
|
|
18
23
|
class CodeReviewTool:
|
19
24
|
name = "code_review"
|
@@ -762,60 +767,89 @@ def extract_code_report(result: str) -> str:
|
|
762
767
|
return result
|
763
768
|
|
764
769
|
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
770
|
+
@app.command("commit")
|
771
|
+
def review_commit(
|
772
|
+
commit: str = typer.Argument(..., help="Commit SHA to review"),
|
773
|
+
root_dir: str = typer.Option(".", "--root-dir", help="Root directory of the codebase"),
|
774
|
+
):
|
775
|
+
"""Review specific commit"""
|
776
|
+
tool = CodeReviewTool()
|
777
|
+
tool_args = {"review_type": "commit", "commit_sha": commit, "root_dir": root_dir}
|
778
|
+
result = tool.execute(tool_args)
|
779
|
+
if result["success"]:
|
780
|
+
PrettyOutput.section("自动代码审查结果:", OutputType.SUCCESS)
|
781
|
+
report = extract_code_report(result["stdout"])
|
782
|
+
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown")
|
783
|
+
else:
|
784
|
+
PrettyOutput.print(result["stderr"], OutputType.WARNING)
|
777
785
|
|
778
|
-
# Current subcommand
|
779
|
-
subparsers.add_parser("current", help="Review current changes")
|
780
786
|
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
787
|
+
@app.command("current")
|
788
|
+
def review_current(
|
789
|
+
root_dir: str = typer.Option(".", "--root-dir", help="Root directory of the codebase"),
|
790
|
+
):
|
791
|
+
"""Review current changes"""
|
792
|
+
tool = CodeReviewTool()
|
793
|
+
tool_args = {"review_type": "current", "root_dir": root_dir}
|
794
|
+
result = tool.execute(tool_args)
|
795
|
+
if result["success"]:
|
796
|
+
PrettyOutput.section("自动代码审查结果:", OutputType.SUCCESS)
|
797
|
+
report = extract_code_report(result["stdout"])
|
798
|
+
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown")
|
799
|
+
else:
|
800
|
+
PrettyOutput.print(result["stderr"], OutputType.WARNING)
|
785
801
|
|
786
|
-
# File subcommand
|
787
|
-
file_parser = subparsers.add_parser("file", help="Review specific file")
|
788
|
-
file_parser.add_argument("file", help="File path to review")
|
789
802
|
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
)
|
803
|
+
@app.command("range")
|
804
|
+
def review_range(
|
805
|
+
start_commit: str = typer.Argument(..., help="Start commit SHA"),
|
806
|
+
end_commit: str = typer.Argument(..., help="End commit SHA"),
|
807
|
+
root_dir: str = typer.Option(".", "--root-dir", help="Root directory of the codebase"),
|
808
|
+
):
|
809
|
+
"""Review commit range"""
|
810
|
+
tool = CodeReviewTool()
|
811
|
+
tool_args = {
|
812
|
+
"review_type": "range",
|
813
|
+
"start_commit": start_commit,
|
814
|
+
"end_commit": end_commit,
|
815
|
+
"root_dir": root_dir,
|
816
|
+
}
|
817
|
+
result = tool.execute(tool_args)
|
818
|
+
if result["success"]:
|
819
|
+
PrettyOutput.section("自动代码审查结果:", OutputType.SUCCESS)
|
820
|
+
report = extract_code_report(result["stdout"])
|
821
|
+
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown")
|
822
|
+
else:
|
823
|
+
PrettyOutput.print(result["stderr"], OutputType.WARNING)
|
794
824
|
|
795
|
-
# Set default subcommand to 'current'
|
796
|
-
parser.set_defaults(type="current")
|
797
|
-
args = parser.parse_args()
|
798
825
|
|
826
|
+
@app.command("file")
|
827
|
+
def review_file(
|
828
|
+
file: str = typer.Argument(..., help="File path to review"),
|
829
|
+
root_dir: str = typer.Option(".", "--root-dir", help="Root directory of the codebase"),
|
830
|
+
):
|
831
|
+
"""Review specific file"""
|
799
832
|
tool = CodeReviewTool()
|
800
|
-
tool_args = {"review_type":
|
801
|
-
if args.type == "commit":
|
802
|
-
tool_args["commit_sha"] = args.commit
|
803
|
-
elif args.type == "range":
|
804
|
-
tool_args["start_commit"] = args.start_commit
|
805
|
-
tool_args["end_commit"] = args.end_commit
|
806
|
-
elif args.type == "file":
|
807
|
-
tool_args["file_path"] = args.file
|
808
|
-
|
833
|
+
tool_args = {"review_type": "file", "file_path": file, "root_dir": root_dir}
|
809
834
|
result = tool.execute(tool_args)
|
810
|
-
|
811
835
|
if result["success"]:
|
812
836
|
PrettyOutput.section("自动代码审查结果:", OutputType.SUCCESS)
|
813
837
|
report = extract_code_report(result["stdout"])
|
814
838
|
PrettyOutput.print(report, OutputType.SUCCESS, lang="markdown")
|
815
|
-
|
816
839
|
else:
|
817
840
|
PrettyOutput.print(result["stderr"], OutputType.WARNING)
|
818
841
|
|
819
842
|
|
843
|
+
def cli():
|
844
|
+
"""Typer application entry point"""
|
845
|
+
init_env("欢迎使用 Jarvis-CodeReview,您的代码审查助手已准备就绪!")
|
846
|
+
app()
|
847
|
+
|
848
|
+
|
849
|
+
def main():
|
850
|
+
"""Main entry point for the script"""
|
851
|
+
cli()
|
852
|
+
|
853
|
+
|
820
854
|
if __name__ == "__main__":
|
821
855
|
main()
|