jarvis-ai-assistant 0.1.5__py3-none-any.whl → 0.1.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of jarvis-ai-assistant might be problematic. Click here for more details.
- jarvis/__init__.py +1 -1
- jarvis/__pycache__/__init__.cpython-313.pyc +0 -0
- jarvis/__pycache__/agent.cpython-313.pyc +0 -0
- jarvis/__pycache__/main.cpython-313.pyc +0 -0
- jarvis/__pycache__/models.cpython-313.pyc +0 -0
- jarvis/__pycache__/utils.cpython-313.pyc +0 -0
- jarvis/__pycache__/zte_llm.cpython-313.pyc +0 -0
- jarvis/agent.py +93 -31
- jarvis/main.py +8 -8
- jarvis/models.py +55 -35
- jarvis/tools/__init__.py +3 -3
- jarvis/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- jarvis/tools/__pycache__/base.cpython-313.pyc +0 -0
- jarvis/tools/__pycache__/shell.cpython-313.pyc +0 -0
- jarvis/tools/__pycache__/sub_agent.cpython-313.pyc +0 -0
- jarvis/tools/__pycache__/user_input.cpython-313.pyc +0 -0
- jarvis/tools/base.py +45 -113
- jarvis/tools/shell.py +62 -48
- jarvis/tools/sub_agent.py +82 -20
- jarvis/tools/user_input.py +74 -0
- jarvis/utils.py +101 -65
- jarvis/zte_llm.py +5 -1
- {jarvis_ai_assistant-0.1.5.dist-info → jarvis_ai_assistant-0.1.6.dist-info}/METADATA +1 -1
- jarvis_ai_assistant-0.1.6.dist-info/RECORD +38 -0
- jarvis/.jarvis +0 -1
- jarvis/tools/python_script.py +0 -150
- jarvis_ai_assistant-0.1.5.dist-info/RECORD +0 -38
- {jarvis_ai_assistant-0.1.5.dist-info → jarvis_ai_assistant-0.1.6.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.5.dist-info → jarvis_ai_assistant-0.1.6.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.5.dist-info → jarvis_ai_assistant-0.1.6.dist-info}/top_level.txt +0 -0
jarvis/tools/shell.py
CHANGED
|
@@ -1,80 +1,94 @@
|
|
|
1
1
|
from typing import Dict, Any
|
|
2
|
-
import
|
|
2
|
+
import os
|
|
3
|
+
import tempfile
|
|
4
|
+
import shlex
|
|
5
|
+
from pathlib import Path
|
|
3
6
|
from ..utils import PrettyOutput, OutputType
|
|
4
7
|
|
|
5
8
|
class ShellTool:
|
|
6
9
|
name = "execute_shell"
|
|
7
10
|
description = """Execute shell commands and return the results.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
|
|
12
|
+
Guidelines:
|
|
13
|
+
1. Filter outputs
|
|
14
|
+
- Use grep/sed for specific data
|
|
15
|
+
- Use head/tail to limit lines
|
|
16
|
+
- Use -q for status checks
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
✓ <START_TOOL_CALL>
|
|
20
|
+
name: execute_shell
|
|
21
|
+
arguments:
|
|
22
|
+
command: ls -l file.txt # specific file
|
|
23
|
+
<END_TOOL_CALL>
|
|
24
|
+
|
|
25
|
+
✗ <START_TOOL_CALL>
|
|
26
|
+
name: execute_shell
|
|
27
|
+
arguments:
|
|
28
|
+
command: ps aux # too much output
|
|
29
|
+
<END_TOOL_CALL>"""
|
|
30
|
+
|
|
22
31
|
parameters = {
|
|
23
32
|
"type": "object",
|
|
24
33
|
"properties": {
|
|
25
34
|
"command": {
|
|
26
35
|
"type": "string",
|
|
27
|
-
"description": "Shell command to execute (
|
|
28
|
-
},
|
|
29
|
-
"timeout": {
|
|
30
|
-
"type": "integer",
|
|
31
|
-
"description": "Command execution timeout in seconds",
|
|
32
|
-
"default": 30
|
|
36
|
+
"description": "Shell command to execute (filter output when possible)"
|
|
33
37
|
}
|
|
34
38
|
},
|
|
35
39
|
"required": ["command"]
|
|
36
40
|
}
|
|
37
41
|
|
|
42
|
+
def _escape_command(self, cmd: str) -> str:
|
|
43
|
+
"""转义命令中的特殊字符"""
|
|
44
|
+
# 将命令中的单引号替换为'"'"'
|
|
45
|
+
return cmd.replace("'", "'\"'\"'")
|
|
46
|
+
|
|
38
47
|
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
39
48
|
"""执行shell命令"""
|
|
40
49
|
try:
|
|
41
|
-
# 获取参数
|
|
42
50
|
command = args["command"]
|
|
43
|
-
timeout = args.get("timeout", 30)
|
|
44
51
|
|
|
45
|
-
#
|
|
46
|
-
|
|
47
|
-
command,
|
|
48
|
-
shell=True,
|
|
49
|
-
capture_output=True,
|
|
50
|
-
text=True,
|
|
51
|
-
timeout=timeout
|
|
52
|
-
)
|
|
52
|
+
# 生成临时文件名
|
|
53
|
+
output_file = os.path.join(tempfile.gettempdir(), f"jarvis_shell_{os.getpid()}.log")
|
|
53
54
|
|
|
54
|
-
#
|
|
55
|
-
|
|
55
|
+
# 转义命令中的特殊字符
|
|
56
|
+
escaped_command = self._escape_command(command)
|
|
57
|
+
|
|
58
|
+
# 修改命令以使用script
|
|
59
|
+
tee_command = f"script -q -c '{escaped_command}' {output_file}"
|
|
56
60
|
|
|
57
|
-
# 添加命令信息
|
|
58
61
|
PrettyOutput.print(f"执行命令: {command}", OutputType.INFO)
|
|
59
|
-
output.append(f"命令: {command}")
|
|
60
|
-
output.append("")
|
|
61
62
|
|
|
62
|
-
#
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
# 执行命令
|
|
64
|
+
return_code = os.system(tee_command)
|
|
65
|
+
|
|
66
|
+
# 读取输出文件
|
|
67
|
+
try:
|
|
68
|
+
with open(output_file, 'r', encoding='utf-8', errors='replace') as f:
|
|
69
|
+
output = f.read()
|
|
70
|
+
# 移除script命令添加的头尾
|
|
71
|
+
if output:
|
|
72
|
+
lines = output.splitlines()
|
|
73
|
+
if len(lines) > 2:
|
|
74
|
+
output = "\n".join(lines[1:-1])
|
|
75
|
+
except Exception as e:
|
|
76
|
+
output = f"读取输出文件失败: {str(e)}"
|
|
77
|
+
finally:
|
|
78
|
+
# 清理临时文件
|
|
79
|
+
Path(output_file).unlink(missing_ok=True)
|
|
65
80
|
|
|
66
81
|
return {
|
|
67
|
-
"success":
|
|
68
|
-
"stdout":
|
|
69
|
-
"stderr":
|
|
70
|
-
"return_code":
|
|
71
|
-
}
|
|
72
|
-
except subprocess.TimeoutExpired:
|
|
73
|
-
return {
|
|
74
|
-
"success": False,
|
|
75
|
-
"error": f"命令执行超时 (>{timeout}秒)"
|
|
82
|
+
"success": return_code == 0,
|
|
83
|
+
"stdout": output,
|
|
84
|
+
"stderr": "",
|
|
85
|
+
"return_code": return_code
|
|
76
86
|
}
|
|
87
|
+
|
|
77
88
|
except Exception as e:
|
|
89
|
+
# 确保清理临时文件
|
|
90
|
+
if 'output_file' in locals():
|
|
91
|
+
Path(output_file).unlink(missing_ok=True)
|
|
78
92
|
return {
|
|
79
93
|
"success": False,
|
|
80
94
|
"error": str(e)
|
jarvis/tools/sub_agent.py
CHANGED
|
@@ -8,35 +8,80 @@ class SubAgentTool:
|
|
|
8
8
|
name = "create_sub_agent"
|
|
9
9
|
description = """Create a sub-agent to handle independent tasks.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
IMPORTANT: Sub-agents start with NO context!
|
|
12
|
+
Must provide complete steps and context.
|
|
13
|
+
|
|
14
|
+
Required:
|
|
15
|
+
1. Context
|
|
16
|
+
- Project background
|
|
17
|
+
- File locations
|
|
18
|
+
- Current standards
|
|
19
|
+
- Requirements
|
|
20
|
+
|
|
21
|
+
2. Steps
|
|
22
|
+
- Clear actions
|
|
23
|
+
- Success criteria
|
|
24
|
+
- Expected output
|
|
25
|
+
|
|
26
|
+
Example (Good):
|
|
27
|
+
<START_TOOL_CALL>
|
|
28
|
+
name: create_sub_agent
|
|
29
|
+
arguments:
|
|
30
|
+
name: CodeAnalyzer
|
|
31
|
+
task: Analyze error handling
|
|
32
|
+
context: |
|
|
33
|
+
Project: Python 3.8+
|
|
34
|
+
File: src/utils.py
|
|
35
|
+
|
|
36
|
+
Steps:
|
|
37
|
+
1. Read file content
|
|
38
|
+
2. Find error patterns
|
|
39
|
+
3. Check consistency
|
|
40
|
+
4. Verify logging
|
|
41
|
+
|
|
42
|
+
Expected:
|
|
43
|
+
- Pattern list
|
|
44
|
+
- Issues found
|
|
45
|
+
- Suggestions
|
|
46
|
+
|
|
47
|
+
Standards:
|
|
48
|
+
- Dict[str, Any] returns
|
|
49
|
+
- PrettyOutput logging
|
|
50
|
+
<END_TOOL_CALL>
|
|
51
|
+
|
|
52
|
+
Example (Bad):
|
|
53
|
+
<START_TOOL_CALL>
|
|
54
|
+
name: create_sub_agent
|
|
55
|
+
arguments:
|
|
56
|
+
name: Analyzer
|
|
57
|
+
task: Check code
|
|
58
|
+
context: Look at utils.py
|
|
59
|
+
<END_TOOL_CALL>
|
|
60
|
+
|
|
61
|
+
Use for:
|
|
62
|
+
✓ Clear, independent tasks
|
|
63
|
+
✓ Well-defined goals
|
|
64
|
+
✗ Vague tasks
|
|
65
|
+
✗ Simple operations"""
|
|
16
66
|
|
|
17
|
-
The sub-agent will:
|
|
18
|
-
1. Inherit all tools from the parent agent
|
|
19
|
-
2. Maintain its own conversation history
|
|
20
|
-
3. Return a comprehensive task summary
|
|
21
|
-
"""
|
|
22
67
|
parameters = {
|
|
23
68
|
"type": "object",
|
|
24
69
|
"properties": {
|
|
25
70
|
"name": {
|
|
26
71
|
"type": "string",
|
|
27
|
-
"description": "
|
|
72
|
+
"description": "Sub-agent name (e.g., 'FileAnalyzer')"
|
|
28
73
|
},
|
|
29
74
|
"task": {
|
|
30
75
|
"type": "string",
|
|
31
|
-
"description": "Task
|
|
76
|
+
"description": "Task with clear steps and goals"
|
|
32
77
|
},
|
|
33
78
|
"context": {
|
|
34
79
|
"type": "string",
|
|
35
|
-
"description": "
|
|
80
|
+
"description": "REQUIRED: Background, steps, and expected results",
|
|
36
81
|
"default": ""
|
|
37
82
|
}
|
|
38
83
|
},
|
|
39
|
-
"required": ["name", "task"]
|
|
84
|
+
"required": ["name", "task", "context"]
|
|
40
85
|
}
|
|
41
86
|
|
|
42
87
|
def __init__(self, model: BaseModel):
|
|
@@ -48,7 +93,13 @@ The sub-agent will:
|
|
|
48
93
|
try:
|
|
49
94
|
name = args["name"]
|
|
50
95
|
task = args["task"]
|
|
51
|
-
context = args.get("context"
|
|
96
|
+
context = args.get("context")
|
|
97
|
+
|
|
98
|
+
if not context:
|
|
99
|
+
return {
|
|
100
|
+
"success": False,
|
|
101
|
+
"error": "Context is required. Please provide complete background and steps."
|
|
102
|
+
}
|
|
52
103
|
|
|
53
104
|
PrettyOutput.print(f"Creating sub-agent '{name}'...", OutputType.INFO)
|
|
54
105
|
|
|
@@ -58,22 +109,33 @@ The sub-agent will:
|
|
|
58
109
|
# Create the sub-agent with the specified name
|
|
59
110
|
sub_agent = Agent(self.model, tool_registry, name=name)
|
|
60
111
|
|
|
61
|
-
# Prepare the task with context
|
|
62
|
-
full_task = f"
|
|
112
|
+
# Prepare the task with context
|
|
113
|
+
full_task = f"""Background and Steps:
|
|
114
|
+
{context}
|
|
115
|
+
|
|
116
|
+
Primary Task:
|
|
117
|
+
{task}
|
|
118
|
+
|
|
119
|
+
Requirements:
|
|
120
|
+
1. Follow the provided steps exactly
|
|
121
|
+
2. Report progress after each step
|
|
122
|
+
3. Highlight any issues or unclear points
|
|
123
|
+
4. Provide detailed results matching expected output"""
|
|
63
124
|
|
|
64
125
|
PrettyOutput.print(f"Sub-agent '{name}' executing task...", OutputType.INFO)
|
|
65
126
|
|
|
127
|
+
|
|
66
128
|
# Execute the task and get the summary
|
|
67
129
|
summary = sub_agent.run(full_task)
|
|
68
|
-
|
|
69
130
|
return {
|
|
70
131
|
"success": True,
|
|
71
|
-
"stdout": f"Sub-agent '{name}' completed
|
|
132
|
+
"stdout": f"Sub-agent '{name}' completed.\n\nResults:\n{summary}",
|
|
72
133
|
"stderr": ""
|
|
73
134
|
}
|
|
74
135
|
|
|
136
|
+
|
|
75
137
|
except Exception as e:
|
|
76
138
|
return {
|
|
77
139
|
"success": False,
|
|
78
|
-
"error": f"Sub-agent
|
|
140
|
+
"error": f"Sub-agent failed: {str(e)}"
|
|
79
141
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from typing import Dict, Any
|
|
2
|
+
from ..utils import PrettyOutput, OutputType, get_multiline_input
|
|
3
|
+
|
|
4
|
+
class UserInputTool:
|
|
5
|
+
name = "ask_user"
|
|
6
|
+
description = """Ask user for information or confirmation.
|
|
7
|
+
|
|
8
|
+
Use this tool when you need:
|
|
9
|
+
1. Additional information
|
|
10
|
+
2. Confirmation before critical actions
|
|
11
|
+
3. User preferences or choices"""
|
|
12
|
+
|
|
13
|
+
parameters = {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"properties": {
|
|
16
|
+
"question": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "Clear question for the user"
|
|
19
|
+
},
|
|
20
|
+
"options": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "Optional: Numbered list of choices",
|
|
23
|
+
"default": ""
|
|
24
|
+
},
|
|
25
|
+
"context": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"description": "Optional: Additional context to help user understand",
|
|
28
|
+
"default": ""
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"required": ["question"]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
35
|
+
"""向用户询问信息并返回响应"""
|
|
36
|
+
try:
|
|
37
|
+
question = args["question"]
|
|
38
|
+
options = args.get("options", "")
|
|
39
|
+
context = args.get("context", "")
|
|
40
|
+
|
|
41
|
+
# 显示问题
|
|
42
|
+
PrettyOutput.section("用户确认", OutputType.USER)
|
|
43
|
+
|
|
44
|
+
# 显示上下文(如果有)
|
|
45
|
+
if context:
|
|
46
|
+
PrettyOutput.print(f"背景: {context}", OutputType.INFO)
|
|
47
|
+
|
|
48
|
+
# 显示问题
|
|
49
|
+
PrettyOutput.print(f"问题: {question}", OutputType.USER)
|
|
50
|
+
|
|
51
|
+
# 显示选项(如果有)
|
|
52
|
+
if options:
|
|
53
|
+
PrettyOutput.print("\n选项:\n" + options, OutputType.INFO)
|
|
54
|
+
|
|
55
|
+
# 获取用户输入
|
|
56
|
+
response = get_multiline_input("请输入您的回答:")
|
|
57
|
+
|
|
58
|
+
if response == "__interrupt__":
|
|
59
|
+
return {
|
|
60
|
+
"success": False,
|
|
61
|
+
"error": "User cancelled the input"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
"success": True,
|
|
66
|
+
"stdout": response,
|
|
67
|
+
"stderr": ""
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
except Exception as e:
|
|
71
|
+
return {
|
|
72
|
+
"success": False,
|
|
73
|
+
"error": f"Failed to get user input: {str(e)}"
|
|
74
|
+
}
|
jarvis/utils.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
import sys
|
|
3
3
|
import time
|
|
4
|
-
import threading
|
|
5
4
|
from typing import Dict, Optional
|
|
6
5
|
from enum import Enum
|
|
7
6
|
from datetime import datetime
|
|
@@ -12,77 +11,112 @@ import os
|
|
|
12
11
|
# 初始化colorama
|
|
13
12
|
colorama.init()
|
|
14
13
|
|
|
15
|
-
class Spinner:
|
|
16
|
-
"""加载动画类"""
|
|
17
|
-
def __init__(self, message: str = "思考中"):
|
|
18
|
-
self.spinner_chars = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
|
|
19
|
-
self.message = message
|
|
20
|
-
self.running = False
|
|
21
|
-
self.spinner_thread = None
|
|
22
|
-
|
|
23
|
-
def _spin(self):
|
|
24
|
-
i = 0
|
|
25
|
-
while self.running:
|
|
26
|
-
sys.stdout.write(f"\r{Fore.BLUE}{self.spinner_chars[i]} {self.message}...{Style.RESET_ALL}")
|
|
27
|
-
sys.stdout.flush()
|
|
28
|
-
time.sleep(0.1)
|
|
29
|
-
i = (i + 1) % len(self.spinner_chars)
|
|
30
|
-
sys.stdout.write("\r" + " " * (len(self.message) + 10) + "\r")
|
|
31
|
-
sys.stdout.flush()
|
|
32
|
-
|
|
33
|
-
def start(self):
|
|
34
|
-
self.running = True
|
|
35
|
-
self.spinner_thread = threading.Thread(target=self._spin)
|
|
36
|
-
self.spinner_thread.start()
|
|
37
|
-
|
|
38
|
-
def stop(self):
|
|
39
|
-
self.running = False
|
|
40
|
-
if self.spinner_thread:
|
|
41
|
-
self.spinner_thread.join()
|
|
42
|
-
|
|
43
14
|
class OutputType(Enum):
|
|
44
|
-
SYSTEM = "system"
|
|
45
|
-
CODE = "code"
|
|
46
|
-
RESULT = "result"
|
|
47
|
-
ERROR = "error"
|
|
48
|
-
INFO = "info"
|
|
15
|
+
SYSTEM = "system" # AI助手消息
|
|
16
|
+
CODE = "code" # 代码相关
|
|
17
|
+
RESULT = "result" # 工具执行结果
|
|
18
|
+
ERROR = "error" # 错误信息
|
|
19
|
+
INFO = "info" # 系统提示
|
|
20
|
+
PLANNING = "planning" # 任务规划
|
|
21
|
+
PROGRESS = "progress" # 执行进度
|
|
22
|
+
SUCCESS = "success" # 成功信息
|
|
23
|
+
WARNING = "warning" # 警告信息
|
|
24
|
+
DEBUG = "debug" # 调试信息
|
|
25
|
+
USER = "user" # 用户输入
|
|
26
|
+
TOOL = "tool" # 工具调用
|
|
49
27
|
|
|
50
28
|
class PrettyOutput:
|
|
51
29
|
"""美化输出类"""
|
|
30
|
+
|
|
31
|
+
# 颜色方案 - 只使用前景色
|
|
32
|
+
COLORS = {
|
|
33
|
+
OutputType.SYSTEM: Fore.CYAN, # 青色 - AI助手
|
|
34
|
+
OutputType.CODE: Fore.GREEN, # 绿色 - 代码
|
|
35
|
+
OutputType.RESULT: Fore.BLUE, # 蓝色 - 结果
|
|
36
|
+
OutputType.ERROR: Fore.RED, # 红色 - 错误
|
|
37
|
+
OutputType.INFO: Fore.YELLOW, # 黄色 - 提示
|
|
38
|
+
OutputType.PLANNING: Fore.MAGENTA, # 紫色 - 规划
|
|
39
|
+
OutputType.PROGRESS: Fore.WHITE, # 白色 - 进度
|
|
40
|
+
OutputType.SUCCESS: Fore.GREEN, # 绿色 - 成功
|
|
41
|
+
OutputType.WARNING: Fore.YELLOW, # 黄色 - 警告
|
|
42
|
+
OutputType.DEBUG: Fore.BLUE, # 蓝色 - 调试
|
|
43
|
+
OutputType.USER: Fore.GREEN, # 绿色 - 用户
|
|
44
|
+
OutputType.TOOL: Fore.YELLOW, # 黄色 - 工具
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# 图标方案
|
|
48
|
+
ICONS = {
|
|
49
|
+
OutputType.SYSTEM: "🤖", # 机器人 - AI助手
|
|
50
|
+
OutputType.CODE: "📝", # 记事本 - 代码
|
|
51
|
+
OutputType.RESULT: "✨", # 闪光 - 结果
|
|
52
|
+
OutputType.ERROR: "❌", # 错误 - 错误
|
|
53
|
+
OutputType.INFO: "ℹ️", # 信息 - 提示
|
|
54
|
+
OutputType.PLANNING: "📋", # 剪贴板 - 规划
|
|
55
|
+
OutputType.PROGRESS: "⏳", # 沙漏 - 进度
|
|
56
|
+
OutputType.SUCCESS: "✅", # 勾选 - 成功
|
|
57
|
+
OutputType.WARNING: "⚠️", # 警告 - 警告
|
|
58
|
+
OutputType.DEBUG: "🔍", # 放大镜 - 调试
|
|
59
|
+
OutputType.USER: "👤", # 用户 - 用户
|
|
60
|
+
OutputType.TOOL: "🔧", # 扳手 - 工具
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# 前缀方案
|
|
64
|
+
PREFIXES = {
|
|
65
|
+
OutputType.SYSTEM: "Assistant",
|
|
66
|
+
OutputType.CODE: "Code",
|
|
67
|
+
OutputType.RESULT: "Result",
|
|
68
|
+
OutputType.ERROR: "Error",
|
|
69
|
+
OutputType.INFO: "Info",
|
|
70
|
+
OutputType.PLANNING: "Plan",
|
|
71
|
+
OutputType.PROGRESS: "Progress",
|
|
72
|
+
OutputType.SUCCESS: "Success",
|
|
73
|
+
OutputType.WARNING: "Warning",
|
|
74
|
+
OutputType.DEBUG: "Debug",
|
|
75
|
+
OutputType.USER: "User",
|
|
76
|
+
OutputType.TOOL: "Tool",
|
|
77
|
+
}
|
|
78
|
+
|
|
52
79
|
@staticmethod
|
|
53
80
|
def format(text: str, output_type: OutputType, timestamp: bool = True) -> str:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
OutputType.RESULT: Fore.BLUE,
|
|
59
|
-
OutputType.ERROR: Fore.RED,
|
|
60
|
-
OutputType.INFO: Fore.YELLOW
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
# 图标映射
|
|
64
|
-
icons = {
|
|
65
|
-
OutputType.SYSTEM: "🤖",
|
|
66
|
-
OutputType.CODE: "📝",
|
|
67
|
-
OutputType.RESULT: "✨",
|
|
68
|
-
OutputType.ERROR: "❌",
|
|
69
|
-
OutputType.INFO: "ℹ️"
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
color = colors.get(output_type, "")
|
|
73
|
-
icon = icons.get(output_type, "")
|
|
81
|
+
"""格式化输出文本"""
|
|
82
|
+
color = PrettyOutput.COLORS.get(output_type, "")
|
|
83
|
+
icon = PrettyOutput.ICONS.get(output_type, "")
|
|
84
|
+
prefix = PrettyOutput.PREFIXES.get(output_type, "")
|
|
74
85
|
|
|
75
|
-
# 添加时间戳
|
|
76
|
-
time_str = f"[{datetime.now().strftime('%H:%M:%S')}] " if timestamp else ""
|
|
86
|
+
# 添加时间戳 - 使用白色
|
|
87
|
+
time_str = f"{Fore.WHITE}[{datetime.now().strftime('%H:%M:%S')}]{Style.RESET_ALL} " if timestamp else ""
|
|
77
88
|
|
|
78
89
|
# 格式化输出
|
|
79
|
-
formatted_text = f"{
|
|
90
|
+
formatted_text = f"{time_str}{color}{icon} {prefix}: {text}{Style.RESET_ALL}"
|
|
80
91
|
|
|
81
92
|
return formatted_text
|
|
82
93
|
|
|
83
94
|
@staticmethod
|
|
84
95
|
def print(text: str, output_type: OutputType, timestamp: bool = True):
|
|
85
|
-
|
|
96
|
+
"""打印格式化的输出"""
|
|
97
|
+
print(PrettyOutput.format(text, output_type, timestamp))
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def section(title: str, output_type: OutputType = OutputType.INFO):
|
|
101
|
+
"""打印带分隔线的段落标题"""
|
|
102
|
+
width = 60
|
|
103
|
+
color = PrettyOutput.COLORS.get(output_type, "")
|
|
104
|
+
print(f"\n{color}" + "=" * width + f"{Style.RESET_ALL}")
|
|
105
|
+
PrettyOutput.print(title.center(width - 10), output_type, timestamp=False)
|
|
106
|
+
print(f"{color}" + "=" * width + f"{Style.RESET_ALL}\n")
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def print_stream(text: str, output_type: OutputType):
|
|
110
|
+
"""打印流式输出,不换行"""
|
|
111
|
+
color = PrettyOutput.COLORS.get(output_type, "")
|
|
112
|
+
sys.stdout.write(f"{color}{text}{Style.RESET_ALL}")
|
|
113
|
+
sys.stdout.flush()
|
|
114
|
+
|
|
115
|
+
@staticmethod
|
|
116
|
+
def print_stream_end():
|
|
117
|
+
"""流式输出结束,打印换行"""
|
|
118
|
+
sys.stdout.write("\n")
|
|
119
|
+
sys.stdout.flush()
|
|
86
120
|
|
|
87
121
|
def get_multiline_input(tip: str) -> str:
|
|
88
122
|
"""获取多行输入"""
|
|
@@ -91,10 +125,13 @@ def get_multiline_input(tip: str) -> str:
|
|
|
91
125
|
|
|
92
126
|
while True:
|
|
93
127
|
try:
|
|
94
|
-
|
|
95
|
-
|
|
128
|
+
prompt = "... " if lines else ">>> "
|
|
129
|
+
sys.stdout.write(f"{Fore.GREEN}{prompt}{Style.RESET_ALL}")
|
|
130
|
+
sys.stdout.flush()
|
|
131
|
+
|
|
132
|
+
line = input().strip()
|
|
96
133
|
if not line:
|
|
97
|
-
if not lines: #
|
|
134
|
+
if not lines: # 如果是第一行就输入空行
|
|
98
135
|
return ""
|
|
99
136
|
break
|
|
100
137
|
|
|
@@ -102,13 +139,12 @@ def get_multiline_input(tip: str) -> str:
|
|
|
102
139
|
|
|
103
140
|
except KeyboardInterrupt:
|
|
104
141
|
PrettyOutput.print("\n输入已取消", OutputType.ERROR)
|
|
105
|
-
return ""
|
|
142
|
+
return "__interrupt__"
|
|
106
143
|
|
|
107
144
|
return "\n".join(lines).strip()
|
|
108
145
|
|
|
109
|
-
|
|
110
146
|
def load_env_from_file():
|
|
111
|
-
"""
|
|
147
|
+
"""从~/.jarvis_env加载环境变量"""
|
|
112
148
|
env_file = Path.home() / ".jarvis_env"
|
|
113
149
|
|
|
114
150
|
if env_file.exists():
|
|
@@ -123,6 +159,6 @@ def load_env_from_file():
|
|
|
123
159
|
except ValueError:
|
|
124
160
|
continue
|
|
125
161
|
except Exception as e:
|
|
126
|
-
print(f"Warning: Failed to read ~/.jarvis_env: {e}")
|
|
162
|
+
PrettyOutput.print(f"Warning: Failed to read ~/.jarvis_env: {e}", OutputType.WARNING)
|
|
127
163
|
|
|
128
164
|
|
jarvis/zte_llm.py
CHANGED
|
@@ -3,6 +3,8 @@ import json
|
|
|
3
3
|
import os
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import Dict, Any, List, Optional
|
|
6
|
+
|
|
7
|
+
from jarvis.utils import OutputType, PrettyOutput
|
|
6
8
|
from .models import BaseModel
|
|
7
9
|
|
|
8
10
|
class ZteLLM(BaseModel):
|
|
@@ -44,7 +46,9 @@ class ZteLLM(BaseModel):
|
|
|
44
46
|
if result["code"]["code"] != "0000":
|
|
45
47
|
raise Exception(f"API Error: {result['code']['msg']}")
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
ret = result["bo"]
|
|
50
|
+
PrettyOutput.print_stream(ret, OutputType.SYSTEM)
|
|
51
|
+
return ret
|
|
48
52
|
|
|
49
53
|
def chat(self, messages: List[Dict[str, Any]], tools: Optional[List[Dict]] = None) -> Dict[str, Any]:
|
|
50
54
|
"""Chat with ZTE LLM"""
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
jarvis/__init__.py,sha256=IB2q6sPGefOsNYLmp5aaOnkS9qWc9ZMY1HQ6V-l-xaY,49
|
|
2
|
+
jarvis/agent.py,sha256=KLeC4oWUYMRXg4QgjyVbfSaJwaIghfJ6KE4JpIS2blI,7225
|
|
3
|
+
jarvis/main.py,sha256=pRwtXWRnbBC3J-xbtuYTxQ0e9JuwU5XxCzbS5SsQESU,6118
|
|
4
|
+
jarvis/models.py,sha256=ZSdUEdVb3aFgvvMtNZuDh3kVXAlA_0CPWv-BzTsLdv8,4508
|
|
5
|
+
jarvis/utils.py,sha256=3hLtv-HcBL8Ngw69cowhARuIFrjcQ6yRP3Y1o9CvtsI,5992
|
|
6
|
+
jarvis/zte_llm.py,sha256=fACFyhEX2ssGC-VOJucBDF_khCFZtyQEC9r9FChae-Q,4631
|
|
7
|
+
jarvis/__pycache__/__init__.cpython-313.pyc,sha256=---ccXWtkwpa6rJNXmjP8vCpz9eCZLk6M1yN3clIrbk,208
|
|
8
|
+
jarvis/__pycache__/agent.cpython-313.pyc,sha256=_i8Bj7p2cBi8G6y8s-7LF-cLO05V3c8AVDoEGbmZbgg,8362
|
|
9
|
+
jarvis/__pycache__/main.cpython-313.pyc,sha256=gJ8eJXVTDuNplc_yjMOxuM17xHwLi6jMtYlB9yiABBc,7963
|
|
10
|
+
jarvis/__pycache__/models.cpython-313.pyc,sha256=7ofJ31hdS9H_VHVpAi_gQGxIcl25i4VWZUpXOinRAnQ,5548
|
|
11
|
+
jarvis/__pycache__/tools.cpython-313.pyc,sha256=lAD4LrnnWzNZQmHXGfZ_2l7oskOpr2_2OC-gdFhxQY8,33933
|
|
12
|
+
jarvis/__pycache__/utils.cpython-313.pyc,sha256=k4jyAlx4tlW0MKLMLzV7OOH9zsKrK0H955kY6M2SuFU,8772
|
|
13
|
+
jarvis/__pycache__/zte_llm.cpython-313.pyc,sha256=OHFPd1MiNkqoncDIFlCj592Y9bQZ8c0Gq6JKJ0enyPA,5553
|
|
14
|
+
jarvis/tools/__init__.py,sha256=Bv3Djt_To60p248ECO2H_LqsTmUriLsq9MDb1Q-uuzA,356
|
|
15
|
+
jarvis/tools/base.py,sha256=rYLrNEpIdmrDm1WavOTyldXZ5dZWVRAmukiMcX40UZU,4436
|
|
16
|
+
jarvis/tools/file_ops.py,sha256=05Vc4u-NGMjLD15WI52eL_nt_RyYt-Z_cXJnnBepf-c,3781
|
|
17
|
+
jarvis/tools/search.py,sha256=dyJmeP_s2tWv5KQejOl-TuVF12B6SXViiXEyTemD1Wo,1412
|
|
18
|
+
jarvis/tools/shell.py,sha256=P0rSaXt-GOXX_-XwkpiLpOXt8Thou4835xGAedxGoGA,2926
|
|
19
|
+
jarvis/tools/sub_agent.py,sha256=t4Lb61_rLyjrbpL4p17Fd1-Or_K12zsNGkAXbXmZPic,3756
|
|
20
|
+
jarvis/tools/user_input.py,sha256=ux3-FE4m5LJIQaoR4qYWeabBK2t0Dk0Irt6_96qUMIc,2313
|
|
21
|
+
jarvis/tools/webpage.py,sha256=UTEomu5j7jbOw8c5az2jsjv5E7LeokWKj1QahvZO7xc,3077
|
|
22
|
+
jarvis/tools/__pycache__/__init__.cpython-313.pyc,sha256=aptY-PF6DpP4xXXHRVfjPV1jQGXAhqcBaTv_ZNei2FA,497
|
|
23
|
+
jarvis/tools/__pycache__/base.cpython-313.pyc,sha256=fEj3a31NMJpaZug4nohtE9OnSCfM3YtzclYYTJvNYJg,6632
|
|
24
|
+
jarvis/tools/__pycache__/file_ops.cpython-313.pyc,sha256=bawv11xhWSj5wCtW0QeJLI-InhUBUXaSkogq6rZzvTQ,3636
|
|
25
|
+
jarvis/tools/__pycache__/python_script.cpython-313.pyc,sha256=8JpryqTovEiTvBlWAK1KjZmPvHUuPc9GT9rTXBEQoJc,6693
|
|
26
|
+
jarvis/tools/__pycache__/rag.cpython-313.pyc,sha256=JH6-PSZRMKAvTZqCwlRXJGClxYXNMs-vetU0q7hBLz0,6064
|
|
27
|
+
jarvis/tools/__pycache__/search.cpython-313.pyc,sha256=VX9zztOwIsPCkYwev0A0XJGyu4Tr0PQcQkbbqx8vfB0,1870
|
|
28
|
+
jarvis/tools/__pycache__/shell.cpython-313.pyc,sha256=0B-mfYwkkZCCCfBQV6Mut0S2ZtW2W4Cykh4rP2W6LJM,3652
|
|
29
|
+
jarvis/tools/__pycache__/sub_agent.cpython-313.pyc,sha256=vkTS0oWAU-We7j7tPs7IbvDcsLh2QNJVQ9Kv_LiMnUs,4021
|
|
30
|
+
jarvis/tools/__pycache__/user_confirmation.cpython-313.pyc,sha256=wK3Ev10lHSUSRvoYmi7A0GzxYkzU-C4Wfhs5qW_HBqs,2271
|
|
31
|
+
jarvis/tools/__pycache__/user_input.cpython-313.pyc,sha256=JjTFOhObKsKF4Pn8KBRuKfV1_Ssj083fjU7Mfc_5z7c,2531
|
|
32
|
+
jarvis/tools/__pycache__/user_interaction.cpython-313.pyc,sha256=RuVZ-pmiPBDywY3efgXSfohMAciC1avMGPmBK5qlnew,3305
|
|
33
|
+
jarvis/tools/__pycache__/webpage.cpython-313.pyc,sha256=VcpkaV8IyOOtebedXjn8ybjr8AglU-3-Cs80yzE4FYo,3628
|
|
34
|
+
jarvis_ai_assistant-0.1.6.dist-info/METADATA,sha256=3ACjmVA3LVSxIHOWf5hHlm5kEvy9mSOqeSgVgIcYJ7s,3690
|
|
35
|
+
jarvis_ai_assistant-0.1.6.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
36
|
+
jarvis_ai_assistant-0.1.6.dist-info/entry_points.txt,sha256=iKu7OMfew9dtfGhW71gIMTg4wvafuPqKb4wyQOnMAGU,44
|
|
37
|
+
jarvis_ai_assistant-0.1.6.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
|
|
38
|
+
jarvis_ai_assistant-0.1.6.dist-info/RECORD,,
|
jarvis/.jarvis
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
- 查看当前git仓库状态,如果有未提交的变更,自动根据当前仓库的文件修改内容总结生成一个git commit,然后执行git push推送到远端仓库,全流程不要询问用户
|