jarvis-ai-assistant 0.1.174__py3-none-any.whl → 0.1.176__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/jarvis_agent/__init__.py +25 -115
- jarvis/jarvis_agent/jarvis.py +4 -2
- jarvis/jarvis_code_agent/code_agent.py +2 -3
- jarvis/jarvis_dev/main.py +6 -6
- jarvis/jarvis_methodology/main.py +4 -4
- jarvis/jarvis_multi_agent/__init__.py +16 -22
- jarvis/jarvis_platform/base.py +47 -29
- jarvis/jarvis_platform/human.py +4 -3
- jarvis/jarvis_platform/kimi.py +9 -87
- jarvis/jarvis_platform/openai.py +8 -9
- jarvis/jarvis_platform/yuanbao.py +16 -22
- jarvis/jarvis_platform_manager/main.py +52 -1
- jarvis/jarvis_tools/ask_codebase.py +7 -1
- jarvis/jarvis_tools/registry.py +8 -8
- jarvis/jarvis_utils/config.py +10 -1
- jarvis/jarvis_utils/embedding.py +1 -10
- jarvis/jarvis_utils/methodology.py +37 -0
- jarvis/jarvis_utils/output.py +51 -62
- {jarvis_ai_assistant-0.1.174.dist-info → jarvis_ai_assistant-0.1.176.dist-info}/METADATA +3 -2
- {jarvis_ai_assistant-0.1.174.dist-info → jarvis_ai_assistant-0.1.176.dist-info}/RECORD +25 -26
- jarvis/jarvis_agent/file_input_handler.py +0 -108
- {jarvis_ai_assistant-0.1.174.dist-info → jarvis_ai_assistant-0.1.176.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.174.dist-info → jarvis_ai_assistant-0.1.176.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.174.dist-info → jarvis_ai_assistant-0.1.176.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.174.dist-info → jarvis_ai_assistant-0.1.176.dist-info}/top_level.txt +0 -0
jarvis/jarvis_platform/openai.py
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import Dict, List, Tuple
|
|
2
|
+
from typing import Dict, Generator, List, Tuple
|
|
3
3
|
import os
|
|
4
4
|
from openai import OpenAI
|
|
5
|
+
from rich.live import Live
|
|
6
|
+
from rich.text import Text
|
|
7
|
+
from rich.panel import Panel
|
|
8
|
+
from rich import box
|
|
5
9
|
from jarvis.jarvis_platform.base import BasePlatform
|
|
6
10
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
7
11
|
|
|
@@ -69,7 +73,7 @@ class OpenAIModel(BasePlatform):
|
|
|
69
73
|
self.system_message = message
|
|
70
74
|
self.messages.append({"role": "system", "content": self.system_message})
|
|
71
75
|
|
|
72
|
-
def chat(self, message: str) -> str:
|
|
76
|
+
def chat(self, message: str) -> Generator[str, None, None]:
|
|
73
77
|
"""Execute conversation"""
|
|
74
78
|
try:
|
|
75
79
|
|
|
@@ -83,21 +87,16 @@ class OpenAIModel(BasePlatform):
|
|
|
83
87
|
) # type: ignore
|
|
84
88
|
|
|
85
89
|
full_response = ""
|
|
86
|
-
|
|
87
90
|
for chunk in response:
|
|
88
91
|
if chunk.choices and chunk.choices[0].delta.content:
|
|
89
92
|
text = chunk.choices[0].delta.content
|
|
90
|
-
if not self.suppress_output:
|
|
91
|
-
PrettyOutput.print_stream(text)
|
|
92
93
|
full_response += text
|
|
93
|
-
|
|
94
|
-
if not self.suppress_output:
|
|
95
|
-
PrettyOutput.print_stream_end()
|
|
94
|
+
yield text
|
|
96
95
|
|
|
97
96
|
# Add assistant reply to history
|
|
98
97
|
self.messages.append({"role": "assistant", "content": full_response})
|
|
99
98
|
|
|
100
|
-
return
|
|
99
|
+
return None
|
|
101
100
|
|
|
102
101
|
except Exception as e:
|
|
103
102
|
PrettyOutput.print(f"对话失败:{str(e)}", OutputType.ERROR)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
from typing import Dict, List, Tuple
|
|
2
|
+
from typing import Dict, Generator, List, Tuple
|
|
3
3
|
import requests
|
|
4
4
|
import json
|
|
5
5
|
import os
|
|
@@ -11,6 +11,10 @@ from PIL import Image
|
|
|
11
11
|
from yaspin import yaspin
|
|
12
12
|
from yaspin.spinners import Spinners
|
|
13
13
|
from yaspin.api import Yaspin
|
|
14
|
+
from rich.live import Live
|
|
15
|
+
from rich.text import Text
|
|
16
|
+
from rich.panel import Panel
|
|
17
|
+
from rich import box
|
|
14
18
|
from jarvis.jarvis_platform.base import BasePlatform
|
|
15
19
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
16
20
|
from jarvis.jarvis_utils.utils import while_success
|
|
@@ -382,12 +386,11 @@ class YuanbaoPlatform(BasePlatform):
|
|
|
382
386
|
PrettyOutput.print(f"生成签名时出错: {str(e)}", OutputType.ERROR)
|
|
383
387
|
raise e
|
|
384
388
|
|
|
385
|
-
def chat(self, message: str) -> str:
|
|
389
|
+
def chat(self, message: str) -> Generator[str, None, None]:
|
|
386
390
|
"""发送消息并获取响应,可选文件附件
|
|
387
391
|
|
|
388
392
|
参数:
|
|
389
393
|
message: 要发送的消息文本
|
|
390
|
-
file_list: 可选的上传和附加文件路径列表
|
|
391
394
|
|
|
392
395
|
返回:
|
|
393
396
|
模型的响应
|
|
@@ -425,7 +428,9 @@ class YuanbaoPlatform(BasePlatform):
|
|
|
425
428
|
self.multimedia = []
|
|
426
429
|
|
|
427
430
|
if self.web:
|
|
428
|
-
payload["supportFunctions"] = ["
|
|
431
|
+
payload["supportFunctions"] = ["openInternetSearch"]
|
|
432
|
+
else:
|
|
433
|
+
payload["supportFunctions"] = ["autoInternetSearch"]
|
|
429
434
|
|
|
430
435
|
# 添加系统消息(如果是第一次对话)
|
|
431
436
|
if self.first_chat and self.system_message:
|
|
@@ -447,9 +452,6 @@ class YuanbaoPlatform(BasePlatform):
|
|
|
447
452
|
error_msg += f", 响应: {response.text}"
|
|
448
453
|
raise Exception(error_msg)
|
|
449
454
|
|
|
450
|
-
full_response = ""
|
|
451
|
-
is_text_block = False
|
|
452
|
-
|
|
453
455
|
# 处理SSE流响应
|
|
454
456
|
for line in response.iter_lines():
|
|
455
457
|
if not line:
|
|
@@ -465,31 +467,23 @@ class YuanbaoPlatform(BasePlatform):
|
|
|
465
467
|
|
|
466
468
|
# 处理文本类型的消息
|
|
467
469
|
if data.get("type") == "text":
|
|
468
|
-
is_text_block = True
|
|
469
470
|
msg = data.get("msg", "")
|
|
470
471
|
if msg:
|
|
471
|
-
|
|
472
|
-
PrettyOutput.print_stream(msg)
|
|
473
|
-
full_response += msg
|
|
472
|
+
yield msg
|
|
474
473
|
|
|
475
|
-
#
|
|
476
|
-
elif data.get("type") == "think"
|
|
474
|
+
# 处理思考中的消息
|
|
475
|
+
elif data.get("type") == "think":
|
|
477
476
|
think_content = data.get("content", "")
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
pass
|
|
477
|
+
if think_content:
|
|
478
|
+
yield think_content
|
|
481
479
|
|
|
482
480
|
except json.JSONDecodeError:
|
|
483
481
|
pass
|
|
484
482
|
|
|
485
483
|
# 检测结束标志
|
|
486
484
|
elif line_str == "data: [DONE]":
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
if not self.suppress_output:
|
|
490
|
-
PrettyOutput.print_stream_end()
|
|
491
|
-
|
|
492
|
-
return full_response
|
|
485
|
+
return None
|
|
486
|
+
return None
|
|
493
487
|
|
|
494
488
|
except Exception as e:
|
|
495
489
|
raise Exception(f"对话失败: {str(e)}")
|
|
@@ -51,6 +51,7 @@ def list_platforms():
|
|
|
51
51
|
def chat_with_model(platform_name: str, model_name: str):
|
|
52
52
|
"""Chat with specified platform and model"""
|
|
53
53
|
registry = PlatformRegistry.get_global_platform_registry()
|
|
54
|
+
conversation_history = [] # 存储对话记录
|
|
54
55
|
|
|
55
56
|
# Create platform instance
|
|
56
57
|
platform = registry.create_platform(platform_name)
|
|
@@ -63,12 +64,13 @@ def chat_with_model(platform_name: str, model_name: str):
|
|
|
63
64
|
platform.set_model_name(model_name)
|
|
64
65
|
platform.set_suppress_output(False)
|
|
65
66
|
PrettyOutput.print(f"连接到 {platform_name} 平台 {model_name} 模型", OutputType.SUCCESS)
|
|
66
|
-
PrettyOutput.print("可用命令: /bye - 退出聊天, /clear - 清除会话, /upload - 上传文件, /shell - 执行shell
|
|
67
|
+
PrettyOutput.print("可用命令: /bye - 退出聊天, /clear - 清除会话, /upload - 上传文件, /shell - 执行shell命令, /save - 保存当前对话, /saveall - 保存所有对话", OutputType.INFO)
|
|
67
68
|
|
|
68
69
|
# Start conversation loop
|
|
69
70
|
while True:
|
|
70
71
|
# Get user input
|
|
71
72
|
user_input = get_multiline_input("")
|
|
73
|
+
conversation_history.append({"role": "user", "content": user_input}) # 记录用户输入
|
|
72
74
|
|
|
73
75
|
# Check if input is cancelled
|
|
74
76
|
if user_input.strip() == "/bye":
|
|
@@ -84,6 +86,7 @@ def chat_with_model(platform_name: str, model_name: str):
|
|
|
84
86
|
try:
|
|
85
87
|
platform.reset()
|
|
86
88
|
platform.set_model_name(model_name) # Reinitialize session
|
|
89
|
+
conversation_history = [] # 重置对话记录
|
|
87
90
|
PrettyOutput.print("会话已清除", OutputType.SUCCESS)
|
|
88
91
|
except Exception as e:
|
|
89
92
|
PrettyOutput.print(f"清除会话失败: {str(e)}", OutputType.ERROR)
|
|
@@ -110,6 +113,52 @@ def chat_with_model(platform_name: str, model_name: str):
|
|
|
110
113
|
PrettyOutput.print(f"上传文件失败: {str(e)}", OutputType.ERROR)
|
|
111
114
|
continue
|
|
112
115
|
|
|
116
|
+
# Check if it is a save command
|
|
117
|
+
if user_input.strip().startswith("/save"):
|
|
118
|
+
try:
|
|
119
|
+
file_path = user_input.strip()[5:].strip()
|
|
120
|
+
if not file_path:
|
|
121
|
+
PrettyOutput.print("请指定保存文件名,例如: /save last_message.txt", OutputType.WARNING)
|
|
122
|
+
continue
|
|
123
|
+
|
|
124
|
+
# Remove quotes if present
|
|
125
|
+
if (file_path.startswith('"') and file_path.endswith('"')) or (file_path.startswith("'") and file_path.endswith("'")):
|
|
126
|
+
file_path = file_path[1:-1]
|
|
127
|
+
|
|
128
|
+
# Write last message content to file
|
|
129
|
+
if conversation_history:
|
|
130
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
131
|
+
last_entry = conversation_history[-1]
|
|
132
|
+
f.write(f"{last_entry['content']}\n")
|
|
133
|
+
PrettyOutput.print(f"最后一条消息内容已保存到 {file_path}", OutputType.SUCCESS)
|
|
134
|
+
else:
|
|
135
|
+
PrettyOutput.print("没有可保存的消息", OutputType.WARNING)
|
|
136
|
+
except Exception as e:
|
|
137
|
+
PrettyOutput.print(f"保存消息失败: {str(e)}", OutputType.ERROR)
|
|
138
|
+
continue
|
|
139
|
+
|
|
140
|
+
# Check if it is a saveall command
|
|
141
|
+
if user_input.strip().startswith("/saveall"):
|
|
142
|
+
try:
|
|
143
|
+
file_path = user_input.strip()[8:].strip()
|
|
144
|
+
if not file_path:
|
|
145
|
+
PrettyOutput.print("请指定保存文件名,例如: /saveall all_conversations.txt", OutputType.WARNING)
|
|
146
|
+
continue
|
|
147
|
+
|
|
148
|
+
# Remove quotes if present
|
|
149
|
+
if (file_path.startswith('"') and file_path.endswith('"')) or (file_path.startswith("'") and file_path.endswith("'")):
|
|
150
|
+
file_path = file_path[1:-1]
|
|
151
|
+
|
|
152
|
+
# Write full conversation history to file
|
|
153
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
154
|
+
for entry in conversation_history:
|
|
155
|
+
f.write(f"{entry['role']}: {entry['content']}\n\n")
|
|
156
|
+
|
|
157
|
+
PrettyOutput.print(f"所有对话已保存到 {file_path}", OutputType.SUCCESS)
|
|
158
|
+
except Exception as e:
|
|
159
|
+
PrettyOutput.print(f"保存所有对话失败: {str(e)}", OutputType.ERROR)
|
|
160
|
+
continue
|
|
161
|
+
|
|
113
162
|
# Check if it is a shell command
|
|
114
163
|
if user_input.strip().startswith("/shell"):
|
|
115
164
|
try:
|
|
@@ -133,6 +182,8 @@ def chat_with_model(platform_name: str, model_name: str):
|
|
|
133
182
|
response = platform.chat_until_success(user_input)
|
|
134
183
|
if not response:
|
|
135
184
|
PrettyOutput.print("没有有效的回复", OutputType.WARNING)
|
|
185
|
+
else:
|
|
186
|
+
conversation_history.append({"role": "assistant", "content": response}) # 记录模型回复
|
|
136
187
|
|
|
137
188
|
except Exception as e:
|
|
138
189
|
PrettyOutput.print(f"聊天失败: {str(e)}", OutputType.ERROR)
|
|
@@ -253,20 +253,26 @@ def main():
|
|
|
253
253
|
```
|
|
254
254
|
python -m jarvis.jarvis_tools.ask_codebase "登录功能在哪个文件实现?" --root_dir /path/to/codebase
|
|
255
255
|
```
|
|
256
|
+
如果没有提供问题参数,则会进入交互式多行输入模式
|
|
256
257
|
"""
|
|
257
258
|
import argparse
|
|
258
259
|
import sys
|
|
260
|
+
from jarvis.jarvis_utils.input import get_multiline_input
|
|
259
261
|
|
|
260
262
|
init_env()
|
|
261
263
|
|
|
262
264
|
# 创建命令行参数解析器
|
|
263
265
|
parser = argparse.ArgumentParser(description="智能代码库查询工具")
|
|
264
|
-
parser.add_argument("question", help="关于代码库的问题")
|
|
266
|
+
parser.add_argument("question", nargs="?", help="关于代码库的问题")
|
|
265
267
|
parser.add_argument("--root_dir", "-d", default=".", help="代码库根目录路径")
|
|
266
268
|
|
|
267
269
|
# 解析命令行参数
|
|
268
270
|
args = parser.parse_args()
|
|
269
271
|
|
|
272
|
+
# 如果没有提供问题参数,使用多行输入
|
|
273
|
+
if not args.question:
|
|
274
|
+
args.question = get_multiline_input("请输入关于代码库的问题:")
|
|
275
|
+
|
|
270
276
|
# 创建并执行工具
|
|
271
277
|
tool = AskCodebaseTool(auto_complete=False)
|
|
272
278
|
result = tool.execute({
|
jarvis/jarvis_tools/registry.py
CHANGED
|
@@ -33,8 +33,8 @@ tool_call_help = f"""
|
|
|
33
33
|
want: 想要从执行结果中获取到的信息,如果工具输出内容过长,会根据此字段尝试提取有效信息
|
|
34
34
|
name: 工具名称
|
|
35
35
|
arguments:
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
param1: 值1
|
|
37
|
+
param2: 值2
|
|
38
38
|
{ct("TOOL_CALL")}
|
|
39
39
|
</format>
|
|
40
40
|
|
|
@@ -49,7 +49,7 @@ arguments:
|
|
|
49
49
|
<rule>
|
|
50
50
|
### 2. 严格遵守格式
|
|
51
51
|
- 完全按照上述格式
|
|
52
|
-
- 使用正确的YAML
|
|
52
|
+
- 使用正确的YAML格式,2个空格作为缩进
|
|
53
53
|
- 包含所有必需参数
|
|
54
54
|
</rule>
|
|
55
55
|
|
|
@@ -72,15 +72,15 @@ arguments:
|
|
|
72
72
|
|
|
73
73
|
<string_format>
|
|
74
74
|
# 📝 字符串参数格式
|
|
75
|
-
始终使用 |
|
|
75
|
+
始终使用 |2 语法表示字符串参数,防止多行字符串行首空格引起歧义:
|
|
76
76
|
|
|
77
77
|
{ot("TOOL_CALL")}
|
|
78
78
|
want: 当前的git状态,期望获取xxx的提交记录
|
|
79
79
|
name: execute_script
|
|
80
80
|
arguments:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
interpreter: bash
|
|
82
|
+
script_cotent: |2
|
|
83
|
+
git status --porcelain
|
|
84
84
|
{ct("TOOL_CALL")}
|
|
85
85
|
</string_format>
|
|
86
86
|
|
|
@@ -96,7 +96,7 @@ arguments:
|
|
|
96
96
|
<common_errors>
|
|
97
97
|
# ⚠️ 常见错误
|
|
98
98
|
- 同时调用多个工具
|
|
99
|
-
- 字符串参数缺少 |
|
|
99
|
+
- 字符串参数缺少 |2
|
|
100
100
|
- 假设工具结果
|
|
101
101
|
- 创建虚构对话
|
|
102
102
|
- 在没有所需信息的情况下继续
|
jarvis/jarvis_utils/config.py
CHANGED
|
@@ -160,4 +160,13 @@ def get_max_big_content_size() -> int:
|
|
|
160
160
|
返回:
|
|
161
161
|
int: 最大大内容大小,默认为1MB
|
|
162
162
|
"""
|
|
163
|
-
return int(os.getenv('JARVIS_MAX_BIG_CONTENT_SIZE', '96000'))
|
|
163
|
+
return int(os.getenv('JARVIS_MAX_BIG_CONTENT_SIZE', '96000'))
|
|
164
|
+
|
|
165
|
+
def get_pretty_output() -> bool:
|
|
166
|
+
"""
|
|
167
|
+
获取是否启用PrettyOutput。
|
|
168
|
+
|
|
169
|
+
返回:
|
|
170
|
+
bool: 如果启用PrettyOutput则返回True,默认为True
|
|
171
|
+
"""
|
|
172
|
+
return os.getenv('JARVIS_PRETTY_OUTPUT', 'false') == 'true'
|
jarvis/jarvis_utils/embedding.py
CHANGED
|
@@ -69,16 +69,7 @@ def split_text_into_chunks(text: str, max_length: int = 512, min_length: int = 5
|
|
|
69
69
|
|
|
70
70
|
# 处理最后一个块
|
|
71
71
|
if current_chunk:
|
|
72
|
-
|
|
73
|
-
chunks.append(current_chunk)
|
|
74
|
-
elif chunks: # 如果最后一个块太短,尝试与前面的块合并
|
|
75
|
-
last_chunk = chunks[-1]
|
|
76
|
-
combined = last_chunk + current_chunk
|
|
77
|
-
combined_tokens = get_context_token_count(combined)
|
|
78
|
-
if combined_tokens <= max_length:
|
|
79
|
-
chunks[-1] = combined
|
|
80
|
-
else:
|
|
81
|
-
chunks.append(current_chunk)
|
|
72
|
+
chunks.append(current_chunk) # 直接添加最后一个块,无论长度如何
|
|
82
73
|
|
|
83
74
|
return chunks
|
|
84
75
|
|
|
@@ -12,6 +12,7 @@ import json
|
|
|
12
12
|
import tempfile
|
|
13
13
|
from typing import Any, Dict, Optional
|
|
14
14
|
|
|
15
|
+
from jarvis.jarvis_platform.base import BasePlatform
|
|
15
16
|
from jarvis.jarvis_utils.config import get_data_dir
|
|
16
17
|
from jarvis.jarvis_utils.output import PrettyOutput, OutputType
|
|
17
18
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
@@ -92,6 +93,42 @@ def _create_methodology_temp_file(methodologies: Dict[str, str]) -> Optional[str
|
|
|
92
93
|
PrettyOutput.print(f"创建方法论临时文件失败: {str(e)}", OutputType.ERROR)
|
|
93
94
|
return None
|
|
94
95
|
|
|
96
|
+
def upload_methodology(platform: BasePlatform) -> bool:
|
|
97
|
+
"""
|
|
98
|
+
上传方法论文件到指定平台
|
|
99
|
+
|
|
100
|
+
参数:
|
|
101
|
+
platform: 平台实例,需实现upload_files方法
|
|
102
|
+
|
|
103
|
+
返回:
|
|
104
|
+
bool: 上传是否成功
|
|
105
|
+
"""
|
|
106
|
+
methodology_dir = _get_methodology_directory()
|
|
107
|
+
if not os.path.exists(methodology_dir):
|
|
108
|
+
PrettyOutput.print("方法论文档不存在", OutputType.WARNING)
|
|
109
|
+
return False
|
|
110
|
+
|
|
111
|
+
methodologies = _load_all_methodologies()
|
|
112
|
+
if not methodologies:
|
|
113
|
+
PrettyOutput.print("没有可用的方法论文档", OutputType.WARNING)
|
|
114
|
+
return False
|
|
115
|
+
|
|
116
|
+
temp_file_path = _create_methodology_temp_file(methodologies)
|
|
117
|
+
if not temp_file_path:
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
try:
|
|
121
|
+
if hasattr(platform, 'upload_files'):
|
|
122
|
+
return platform.upload_files([temp_file_path])
|
|
123
|
+
return False
|
|
124
|
+
finally:
|
|
125
|
+
if temp_file_path and os.path.exists(temp_file_path):
|
|
126
|
+
try:
|
|
127
|
+
os.remove(temp_file_path)
|
|
128
|
+
except Exception:
|
|
129
|
+
pass
|
|
130
|
+
|
|
131
|
+
|
|
95
132
|
def load_methodology(user_input: str, tool_registery: Optional[Any] = None) -> str:
|
|
96
133
|
"""
|
|
97
134
|
加载方法论并上传到大模型。
|
jarvis/jarvis_utils/output.py
CHANGED
|
@@ -17,7 +17,9 @@ from rich.syntax import Syntax
|
|
|
17
17
|
from rich.style import Style as RichStyle
|
|
18
18
|
from pygments.lexers import guess_lexer
|
|
19
19
|
from pygments.util import ClassNotFound
|
|
20
|
+
from jarvis.jarvis_utils.config import get_pretty_output
|
|
20
21
|
from jarvis.jarvis_utils.globals import console, get_agent_list
|
|
22
|
+
# from rich.box import HEAVY
|
|
21
23
|
class OutputType(Enum):
|
|
22
24
|
"""
|
|
23
25
|
输出类型枚举,用于分类和样式化不同类型的消息。
|
|
@@ -125,7 +127,7 @@ class PrettyOutput:
|
|
|
125
127
|
except (ClassNotFound, Exception):
|
|
126
128
|
return default_lang
|
|
127
129
|
@staticmethod
|
|
128
|
-
def _format(output_type: OutputType, timestamp: bool = True) ->
|
|
130
|
+
def _format(output_type: OutputType, timestamp: bool = True) -> str:
|
|
129
131
|
"""
|
|
130
132
|
使用时间戳和图标格式化输出头。
|
|
131
133
|
|
|
@@ -136,14 +138,13 @@ class PrettyOutput:
|
|
|
136
138
|
返回:
|
|
137
139
|
Text: 格式化后的rich Text对象
|
|
138
140
|
"""
|
|
139
|
-
|
|
141
|
+
icon = PrettyOutput._ICONS.get(output_type, "")
|
|
142
|
+
formatted = f"{icon} "
|
|
140
143
|
if timestamp:
|
|
141
|
-
formatted
|
|
144
|
+
formatted+=f"[{datetime.now().strftime('%H:%M:%S')}][{output_type.value}]"
|
|
142
145
|
agent_info = get_agent_list()
|
|
143
146
|
if agent_info:
|
|
144
|
-
formatted
|
|
145
|
-
icon = PrettyOutput._ICONS.get(output_type, "")
|
|
146
|
-
formatted.append(f" {icon} ", style=output_type.value)
|
|
147
|
+
formatted+=f"[{agent_info}]"
|
|
147
148
|
return formatted
|
|
148
149
|
@staticmethod
|
|
149
150
|
def print(text: str, output_type: OutputType, timestamp: bool = True, lang: Optional[str] = None, traceback: bool = False):
|
|
@@ -158,35 +159,52 @@ class PrettyOutput:
|
|
|
158
159
|
traceback: 是否显示错误的回溯信息
|
|
159
160
|
"""
|
|
160
161
|
styles = {
|
|
161
|
-
OutputType.SYSTEM:
|
|
162
|
-
OutputType.CODE:
|
|
163
|
-
OutputType.RESULT:
|
|
164
|
-
OutputType.ERROR:
|
|
165
|
-
OutputType.INFO:
|
|
166
|
-
OutputType.PLANNING:
|
|
167
|
-
OutputType.PROGRESS:
|
|
168
|
-
OutputType.SUCCESS:
|
|
169
|
-
OutputType.WARNING:
|
|
170
|
-
OutputType.DEBUG:
|
|
171
|
-
OutputType.USER:
|
|
172
|
-
OutputType.TOOL:
|
|
162
|
+
OutputType.SYSTEM: dict( bgcolor="#1e2b3c"),
|
|
163
|
+
OutputType.CODE: dict( bgcolor="#1c2b1c"),
|
|
164
|
+
OutputType.RESULT: dict( bgcolor="#1c1c2b"),
|
|
165
|
+
OutputType.ERROR: dict( bgcolor="#2b1c1c"),
|
|
166
|
+
OutputType.INFO: dict( bgcolor="#2b2b1c", meta={"icon": "ℹ️"}),
|
|
167
|
+
OutputType.PLANNING: dict( bgcolor="#2b1c2b"),
|
|
168
|
+
OutputType.PROGRESS: dict( bgcolor="#1c1c1c"),
|
|
169
|
+
OutputType.SUCCESS: dict( bgcolor="#1c2b1c"),
|
|
170
|
+
OutputType.WARNING: dict( bgcolor="#2b2b1c"),
|
|
171
|
+
OutputType.DEBUG: dict( bgcolor="#1c1c1c"),
|
|
172
|
+
OutputType.USER: dict( bgcolor="#1c2b2b"),
|
|
173
|
+
OutputType.TOOL: dict( bgcolor="#1c2b2b"),
|
|
173
174
|
}
|
|
175
|
+
|
|
176
|
+
header_styles = {
|
|
177
|
+
OutputType.SYSTEM: RichStyle(color="bright_cyan", bgcolor="#1e2b3c", frame=True, meta={"icon": "🤖"}),
|
|
178
|
+
OutputType.CODE: RichStyle(color="green", bgcolor="#1c2b1c", frame=True, meta={"icon": "📝"}),
|
|
179
|
+
OutputType.RESULT: RichStyle(color="bright_blue", bgcolor="#1c1c2b", frame=True, meta={"icon": "✨"}),
|
|
180
|
+
OutputType.ERROR: RichStyle(color="red", frame=True, bgcolor="#2b1c1c", meta={"icon": "❌"}),
|
|
181
|
+
OutputType.INFO: RichStyle(color="gold1", frame=True, bgcolor="#2b2b1c", meta={"icon": "ℹ️"}),
|
|
182
|
+
OutputType.PLANNING: RichStyle(color="purple", bold=True, frame=True, bgcolor="#2b1c2b", meta={"icon": "📋"}),
|
|
183
|
+
OutputType.PROGRESS: RichStyle(color="white", encircle=True, frame=True, bgcolor="#1c1c1c", meta={"icon": "⏳"}),
|
|
184
|
+
OutputType.SUCCESS: RichStyle(color="bright_green", bold=True, strike=False, bgcolor="#1c2b1c", meta={"icon": "✅"}),
|
|
185
|
+
OutputType.WARNING: RichStyle(color="yellow", bold=True, blink2=True, bgcolor="#2b2b1c", meta={"icon": "⚠️"}),
|
|
186
|
+
OutputType.DEBUG: RichStyle(color="grey58", dim=True, conceal=True, bgcolor="#1c1c1c", meta={"icon": "🔍"}),
|
|
187
|
+
OutputType.USER: RichStyle(color="spring_green2", frame=True, bgcolor="#1c2b2b", meta={"icon": "👤"}),
|
|
188
|
+
OutputType.TOOL: RichStyle(color="dark_sea_green4", bgcolor="#1c2b2b", frame=True, meta={"icon": "🔧"}),
|
|
189
|
+
}
|
|
190
|
+
|
|
174
191
|
lang = lang if lang is not None else PrettyOutput._detect_language(text, default_lang='markdown')
|
|
175
|
-
header = PrettyOutput._format(output_type, timestamp)
|
|
176
|
-
content = Syntax(text, lang, theme="
|
|
192
|
+
header = Text(PrettyOutput._format(output_type, timestamp), style=header_styles[output_type])
|
|
193
|
+
content = Syntax(text, lang, theme="dracula", word_wrap=True, background_color=styles[output_type]["bgcolor"])
|
|
177
194
|
panel = Panel(
|
|
178
195
|
content,
|
|
179
|
-
|
|
180
|
-
border_style=styles[output_type],
|
|
196
|
+
border_style=header_styles[output_type],
|
|
181
197
|
title=header,
|
|
182
198
|
title_align="left",
|
|
183
199
|
padding=(0, 0),
|
|
184
200
|
highlight=True,
|
|
185
|
-
# box=HEAVY,
|
|
186
201
|
)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
202
|
+
if get_pretty_output():
|
|
203
|
+
console.print(panel)
|
|
204
|
+
else:
|
|
205
|
+
console.print(header)
|
|
206
|
+
console.print(content)
|
|
207
|
+
if traceback:
|
|
190
208
|
console.print_exception()
|
|
191
209
|
@staticmethod
|
|
192
210
|
def section(title: str, output_type: OutputType = OutputType.INFO):
|
|
@@ -197,42 +215,13 @@ class PrettyOutput:
|
|
|
197
215
|
title: 章节标题文本
|
|
198
216
|
output_type: 输出类型(影响样式)
|
|
199
217
|
"""
|
|
218
|
+
text = Text(title, style=output_type.value, justify="center")
|
|
200
219
|
panel = Panel(
|
|
201
|
-
|
|
220
|
+
text,
|
|
202
221
|
border_style=output_type.value
|
|
203
222
|
)
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
"""
|
|
210
|
-
打印流式输出,不带换行符。
|
|
211
|
-
|
|
212
|
-
参数:
|
|
213
|
-
text: 要打印的文本
|
|
214
|
-
"""
|
|
215
|
-
style = RichStyle(color="bright_cyan", bold=True, frame=True, meta={"icon": "🤖"})
|
|
216
|
-
if is_thinking:
|
|
217
|
-
style = RichStyle(color="grey58", italic=True, frame=True, meta={"icon": "🤖"})
|
|
218
|
-
console.print(text, style=style, end="")
|
|
219
|
-
@staticmethod
|
|
220
|
-
def print_stream_end():
|
|
221
|
-
"""
|
|
222
|
-
结束流式输出,带换行符。
|
|
223
|
-
"""
|
|
224
|
-
end_style = PrettyOutput._get_style(OutputType.SUCCESS)
|
|
225
|
-
console.print("\n", style=end_style)
|
|
226
|
-
console.file.flush()
|
|
227
|
-
@staticmethod
|
|
228
|
-
def _get_style(output_type: OutputType) -> RichStyle:
|
|
229
|
-
"""
|
|
230
|
-
获取预定义的RichStyle用于输出类型。
|
|
231
|
-
|
|
232
|
-
参数:
|
|
233
|
-
output_type: 要获取样式的输出类型
|
|
234
|
-
|
|
235
|
-
返回:
|
|
236
|
-
RichStyle: 对应的样式
|
|
237
|
-
"""
|
|
238
|
-
return console.get_style(output_type.value)
|
|
223
|
+
if get_pretty_output():
|
|
224
|
+
console.print(panel)
|
|
225
|
+
else:
|
|
226
|
+
console.print(text)
|
|
227
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jarvis-ai-assistant
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.176
|
|
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
|
|
@@ -213,7 +213,8 @@ OPENAI_API_BASE=https://api.openai.com/v1 # 可选,默认为官方API地址
|
|
|
213
213
|
| `JARVIS_CONFIRM_BEFORE_APPLY_PATCH` | true | 应用补丁前是否需要确认 |
|
|
214
214
|
| `JARVIS_MAX_TOOL_CALL_COUNT` | 20 | 最大连续工具调用次数 |
|
|
215
215
|
| `JARVIS_AUTO_UPDATE` | true | 是否自动更新Jarvis(仅在以git仓库方式安装时有效) |
|
|
216
|
-
| `JARVIS_MAX_BIG_CONTENT_SIZE` |
|
|
216
|
+
| `JARVIS_MAX_BIG_CONTENT_SIZE` | 96000 | 最大大内容大小 |
|
|
217
|
+
| `JARVIS_PRETTY_OUTPUT` | false | 是否启用PrettyOutput |
|
|
217
218
|
|
|
218
219
|
所有配置编写到`~/.jarvis/env`文件中即可生效。
|
|
219
220
|
|