jarvis-ai-assistant 0.3.26__py3-none-any.whl → 0.3.28__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/__init__.py +303 -177
- jarvis/jarvis_agent/agent_manager.py +6 -0
- jarvis/jarvis_agent/config.py +92 -0
- jarvis/jarvis_agent/config_editor.py +1 -1
- jarvis/jarvis_agent/event_bus.py +48 -0
- jarvis/jarvis_agent/file_methodology_manager.py +1 -3
- jarvis/jarvis_agent/jarvis.py +77 -36
- jarvis/jarvis_agent/memory_manager.py +70 -3
- jarvis/jarvis_agent/prompt_manager.py +82 -0
- jarvis/jarvis_agent/run_loop.py +130 -0
- jarvis/jarvis_agent/shell_input_handler.py +1 -1
- jarvis/jarvis_agent/task_analyzer.py +89 -11
- jarvis/jarvis_agent/task_manager.py +26 -0
- jarvis/jarvis_agent/user_interaction.py +42 -0
- jarvis/jarvis_code_agent/code_agent.py +18 -3
- jarvis/jarvis_code_agent/lint.py +5 -5
- jarvis/jarvis_code_analysis/code_review.py +0 -1
- jarvis/jarvis_data/config_schema.json +7 -6
- jarvis/jarvis_git_squash/main.py +6 -1
- jarvis/jarvis_git_utils/git_commiter.py +51 -16
- jarvis/jarvis_mcp/stdio_mcp_client.py +1 -1
- jarvis/jarvis_memory_organizer/memory_organizer.py +2 -5
- jarvis/jarvis_methodology/main.py +0 -2
- jarvis/jarvis_multi_agent/__init__.py +3 -3
- jarvis/jarvis_platform/base.py +5 -6
- jarvis/jarvis_platform/registry.py +1 -1
- jarvis/jarvis_platform/yuanbao.py +0 -1
- jarvis/jarvis_platform_manager/main.py +28 -11
- jarvis/jarvis_platform_manager/service.py +1 -1
- jarvis/jarvis_rag/cli.py +1 -1
- jarvis/jarvis_rag/embedding_manager.py +0 -1
- jarvis/jarvis_rag/llm_interface.py +0 -3
- jarvis/jarvis_smart_shell/main.py +0 -1
- jarvis/jarvis_stats/cli.py +15 -35
- jarvis/jarvis_stats/stats.py +178 -51
- jarvis/jarvis_tools/clear_memory.py +1 -3
- jarvis/jarvis_tools/cli/main.py +0 -1
- jarvis/jarvis_tools/edit_file.py +0 -1
- jarvis/jarvis_tools/generate_new_tool.py +3 -5
- jarvis/jarvis_tools/registry.py +17 -3
- jarvis/jarvis_tools/retrieve_memory.py +2 -3
- jarvis/jarvis_tools/save_memory.py +3 -3
- jarvis/jarvis_tools/search_web.py +2 -2
- jarvis/jarvis_tools/sub_agent.py +114 -85
- jarvis/jarvis_tools/sub_code_agent.py +29 -7
- jarvis/jarvis_tools/virtual_tty.py +3 -14
- jarvis/jarvis_utils/builtin_replace_map.py +4 -4
- jarvis/jarvis_utils/config.py +44 -15
- jarvis/jarvis_utils/fzf.py +56 -0
- jarvis/jarvis_utils/git_utils.py +1 -1
- jarvis/jarvis_utils/globals.py +1 -2
- jarvis/jarvis_utils/input.py +0 -3
- jarvis/jarvis_utils/methodology.py +3 -5
- jarvis/jarvis_utils/output.py +1 -1
- jarvis/jarvis_utils/utils.py +117 -27
- {jarvis_ai_assistant-0.3.26.dist-info → jarvis_ai_assistant-0.3.28.dist-info}/METADATA +2 -3
- {jarvis_ai_assistant-0.3.26.dist-info → jarvis_ai_assistant-0.3.28.dist-info}/RECORD +62 -56
- {jarvis_ai_assistant-0.3.26.dist-info → jarvis_ai_assistant-0.3.28.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.3.26.dist-info → jarvis_ai_assistant-0.3.28.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.3.26.dist-info → jarvis_ai_assistant-0.3.28.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.26.dist-info → jarvis_ai_assistant-0.3.28.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,5 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
import json
|
3
|
-
import random
|
4
3
|
from pathlib import Path
|
5
4
|
from typing import Any, Dict, List, Optional
|
6
5
|
|
@@ -170,7 +169,7 @@ class RetrieveMemoryTool:
|
|
170
169
|
pass
|
171
170
|
|
172
171
|
# 格式化为Markdown输出
|
173
|
-
markdown_output =
|
172
|
+
markdown_output = "# 记忆检索结果\n\n"
|
174
173
|
markdown_output += f"**检索到 {len(all_memories)} 条记忆**\n\n"
|
175
174
|
|
176
175
|
if tags:
|
@@ -201,7 +200,7 @@ class RetrieveMemoryTool:
|
|
201
200
|
if k not in ["id", "type", "tags", "created_at", "content"]
|
202
201
|
}
|
203
202
|
if metadata:
|
204
|
-
markdown_output +=
|
203
|
+
markdown_output += "**其他信息**:\n"
|
205
204
|
for key, value in metadata.items():
|
206
205
|
markdown_output += f"- {key}: {value}\n"
|
207
206
|
markdown_output += "\n"
|
@@ -3,7 +3,7 @@ import json
|
|
3
3
|
import time
|
4
4
|
from datetime import datetime
|
5
5
|
from pathlib import Path
|
6
|
-
from typing import Any, Dict
|
6
|
+
from typing import Any, Dict
|
7
7
|
|
8
8
|
from jarvis.jarvis_utils.config import get_data_dir
|
9
9
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
@@ -157,8 +157,8 @@ class SaveMemoryTool:
|
|
157
157
|
success_count += 1
|
158
158
|
|
159
159
|
# 打印单条记忆保存信息
|
160
|
-
|
161
|
-
|
160
|
+
memory_data["memory_type"]
|
161
|
+
memory_data.get("tags", [])
|
162
162
|
|
163
163
|
except Exception as e:
|
164
164
|
failed_count += 1
|
@@ -54,7 +54,7 @@ class SearchWebTool:
|
|
54
54
|
break
|
55
55
|
|
56
56
|
url = r["href"]
|
57
|
-
|
57
|
+
r.get("title", url)
|
58
58
|
|
59
59
|
try:
|
60
60
|
|
@@ -79,7 +79,7 @@ class SearchWebTool:
|
|
79
79
|
"success": False,
|
80
80
|
}
|
81
81
|
|
82
|
-
|
82
|
+
"\n".join(f" - {u}" for u in visited_urls)
|
83
83
|
|
84
84
|
summary_prompt = f"请为查询“{query}”总结以下内容:\n\n{full_content}"
|
85
85
|
|
jarvis/jarvis_tools/sub_agent.py
CHANGED
@@ -4,15 +4,17 @@ sub_agent 工具
|
|
4
4
|
将子任务交给通用 Agent 执行,并返回执行结果。
|
5
5
|
|
6
6
|
约定:
|
7
|
-
-
|
8
|
-
-
|
7
|
+
- 必填参数:task, name, background, system_prompt, summary_prompt, use_tools
|
8
|
+
- 继承父 Agent 的部分配置:model_group、input_handler、execute_tool_confirm、multiline_inputer;其他参数需显式提供
|
9
9
|
- 子Agent必须自动完成(auto_complete=True)且需要summary(need_summary=True)
|
10
10
|
"""
|
11
|
-
from typing import Any, Dict
|
11
|
+
from typing import Any, Dict
|
12
12
|
import json
|
13
13
|
|
14
|
-
from jarvis.jarvis_agent import Agent
|
14
|
+
from jarvis.jarvis_agent import Agent
|
15
15
|
from jarvis.jarvis_utils.globals import delete_agent
|
16
|
+
from jarvis.jarvis_tools.registry import ToolRegistry
|
17
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
16
18
|
|
17
19
|
|
18
20
|
class SubAgentTool:
|
@@ -25,7 +27,7 @@ class SubAgentTool:
|
|
25
27
|
|
26
28
|
# 必须与文件名一致,供 ToolRegistry 自动注册
|
27
29
|
name = "sub_agent"
|
28
|
-
description = "将子任务交给通用 Agent
|
30
|
+
description = "将子任务交给通用 Agent 执行,并返回执行结果(继承父Agent部分配置:model_group、input_handler、execute_tool_confirm、multiline_inputer;其他参数需显式提供,自动完成并生成总结)。"
|
29
31
|
parameters = {
|
30
32
|
"type": "object",
|
31
33
|
"properties": {
|
@@ -33,12 +35,42 @@ class SubAgentTool:
|
|
33
35
|
"type": "string",
|
34
36
|
"description": "要执行的子任务内容(必填)",
|
35
37
|
},
|
38
|
+
"name": {
|
39
|
+
"type": "string",
|
40
|
+
"description": "子Agent名称(必填)",
|
41
|
+
},
|
36
42
|
"background": {
|
37
43
|
"type": "string",
|
38
|
-
"description": "
|
44
|
+
"description": "任务背景与已知信息(必填,将与任务一并提供给子Agent)",
|
45
|
+
},
|
46
|
+
"system_prompt": {
|
47
|
+
"type": "string",
|
48
|
+
"description": "覆盖子Agent的系统提示词(必填)",
|
49
|
+
},
|
50
|
+
"summary_prompt": {
|
51
|
+
"type": "string",
|
52
|
+
"description": "覆盖子Agent的总结提示词(必填)",
|
53
|
+
},
|
54
|
+
"use_tools": {
|
55
|
+
"type": "array",
|
56
|
+
"items": {"type": "string"},
|
57
|
+
"description": "限制子Agent可用的工具名称列表(必填)。兼容以逗号分隔的字符串输入。可用的工具列表:"
|
58
|
+
+ "\n".join(
|
59
|
+
[
|
60
|
+
t["name"] + ": " + t["description"]
|
61
|
+
for t in ToolRegistry().get_all_tools()
|
62
|
+
]
|
63
|
+
),
|
39
64
|
},
|
40
65
|
},
|
41
|
-
"required": [
|
66
|
+
"required": [
|
67
|
+
"task",
|
68
|
+
"name",
|
69
|
+
"background",
|
70
|
+
"system_prompt",
|
71
|
+
"summary_prompt",
|
72
|
+
"use_tools",
|
73
|
+
],
|
42
74
|
}
|
43
75
|
|
44
76
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
@@ -64,105 +96,102 @@ class SubAgentTool:
|
|
64
96
|
f"背景信息:\n{background}\n\n任务:\n{task}" if background else task
|
65
97
|
)
|
66
98
|
|
67
|
-
#
|
68
|
-
parent_agent = args.get("agent")
|
69
|
-
# 如未注入父Agent,尝试从全局获取当前或任一已注册Agent
|
70
|
-
if parent_agent is None:
|
71
|
-
try:
|
72
|
-
from jarvis.jarvis_utils import globals as G # 延迟导入避免循环
|
73
|
-
|
74
|
-
curr = getattr(G, "current_agent_name", "")
|
75
|
-
if curr:
|
76
|
-
parent_agent = getattr(G, "global_agents", {}).get(curr)
|
77
|
-
if parent_agent is None and getattr(G, "global_agents", {}):
|
78
|
-
try:
|
79
|
-
parent_agent = next(iter(G.global_agents.values()))
|
80
|
-
except Exception:
|
81
|
-
parent_agent = None
|
82
|
-
except Exception:
|
83
|
-
parent_agent = None
|
84
|
-
# 默认/全局
|
85
|
-
system_prompt = origin_agent_system_prompt
|
99
|
+
# 不继承父Agent,所有关键参数必须由调用方显式提供
|
86
100
|
need_summary = True
|
87
101
|
auto_complete = True
|
88
102
|
|
89
|
-
#
|
90
|
-
|
91
|
-
summary_prompt =
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
103
|
+
# 读取并校验必填参数
|
104
|
+
system_prompt = str(args.get("system_prompt", "")).strip()
|
105
|
+
summary_prompt = str(args.get("summary_prompt", "")).strip()
|
106
|
+
agent_name = str(args.get("name", "")).strip()
|
107
|
+
|
108
|
+
# 解析可用工具列表(支持数组或以逗号分隔的字符串)
|
109
|
+
_use_tools = args.get("use_tools", None)
|
96
110
|
use_tools: list[str] = []
|
111
|
+
if isinstance(_use_tools, list):
|
112
|
+
use_tools = [str(x).strip() for x in _use_tools if str(x).strip()]
|
113
|
+
elif isinstance(_use_tools, str):
|
114
|
+
use_tools = [s.strip() for s in _use_tools.split(",") if s.strip()]
|
115
|
+
else:
|
116
|
+
use_tools = []
|
117
|
+
|
118
|
+
errors = []
|
119
|
+
if not system_prompt:
|
120
|
+
errors.append("system_prompt 不能为空")
|
121
|
+
if not summary_prompt:
|
122
|
+
errors.append("summary_prompt 不能为空")
|
123
|
+
if not agent_name:
|
124
|
+
errors.append("name 不能为空")
|
125
|
+
if not use_tools:
|
126
|
+
errors.append("use_tools 不能为空")
|
127
|
+
if not background:
|
128
|
+
errors.append("background 不能为空")
|
129
|
+
|
130
|
+
if errors:
|
131
|
+
return {
|
132
|
+
"success": False,
|
133
|
+
"stdout": "",
|
134
|
+
"stderr": "; ".join(errors),
|
135
|
+
}
|
97
136
|
|
137
|
+
# 基于父Agent(如有)继承部分配置后创建子Agent
|
138
|
+
parent_agent = args.get("agent", None)
|
139
|
+
parent_model_group = None
|
140
|
+
parent_input_handler = None
|
141
|
+
parent_execute_tool_confirm = None
|
142
|
+
parent_multiline_inputer = None
|
98
143
|
try:
|
99
144
|
if parent_agent is not None:
|
100
|
-
# 继承模型组
|
101
145
|
if getattr(parent_agent, "model", None):
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
parent_agent, "execute_tool_confirm", None
|
107
|
-
)
|
108
|
-
use_methodology = getattr(parent_agent, "use_methodology", None)
|
109
|
-
use_analysis = getattr(parent_agent, "use_analysis", None)
|
110
|
-
force_save_memory = getattr(parent_agent, "force_save_memory", None)
|
111
|
-
# 继承工具使用集(名称列表)
|
112
|
-
parent_registry = parent_agent.get_tool_registry()
|
113
|
-
if parent_registry:
|
114
|
-
for t in parent_registry.get_all_tools():
|
115
|
-
if isinstance(t, dict) and t.get("name"):
|
116
|
-
use_tools.append(str(t["name"]))
|
146
|
+
parent_model_group = getattr(parent_agent.model, "model_group", None)
|
147
|
+
parent_input_handler = getattr(parent_agent, "input_handler", None)
|
148
|
+
parent_execute_tool_confirm = getattr(parent_agent, "execute_tool_confirm", None)
|
149
|
+
parent_multiline_inputer = getattr(parent_agent, "multiline_inputer", None)
|
117
150
|
except Exception:
|
118
|
-
#
|
151
|
+
# 安全兜底:无法从父Agent获取配置则保持为None,使用系统默认
|
119
152
|
pass
|
120
153
|
|
121
|
-
# 为避免交互阻塞:提供自动确认与空输入处理器
|
122
|
-
def _auto_confirm(tip: str, default: bool = True) -> bool:
|
123
|
-
return default
|
124
|
-
|
125
|
-
# 创建子Agent(其余配置使用默认/全局)
|
126
154
|
agent = Agent(
|
127
155
|
system_prompt=system_prompt,
|
128
|
-
name=
|
156
|
+
name=agent_name,
|
129
157
|
description="Temporary sub agent for executing a subtask",
|
130
|
-
|
131
|
-
|
132
|
-
summary_prompt=summary_prompt, # 继承父Agent总结提示词(如可用)
|
158
|
+
model_group=parent_model_group,
|
159
|
+
summary_prompt=summary_prompt,
|
133
160
|
auto_complete=auto_complete,
|
134
|
-
output_handler=None,
|
135
|
-
use_tools=None,
|
136
|
-
input_handler=
|
137
|
-
execute_tool_confirm=
|
161
|
+
output_handler=None,
|
162
|
+
use_tools=None,
|
163
|
+
input_handler=parent_input_handler,
|
164
|
+
execute_tool_confirm=parent_execute_tool_confirm,
|
138
165
|
need_summary=need_summary,
|
139
|
-
multiline_inputer=
|
140
|
-
use_methodology=
|
141
|
-
use_analysis=
|
142
|
-
force_save_memory=
|
166
|
+
multiline_inputer=parent_multiline_inputer,
|
167
|
+
use_methodology=None,
|
168
|
+
use_analysis=None,
|
169
|
+
force_save_memory=None,
|
143
170
|
files=None,
|
144
|
-
confirm_callback=_auto_confirm, # 自动确认
|
145
171
|
)
|
146
172
|
|
147
|
-
#
|
173
|
+
# 设置可用工具列表
|
174
|
+
try:
|
175
|
+
agent.set_use_tools(use_tools)
|
176
|
+
except Exception:
|
177
|
+
pass
|
178
|
+
|
179
|
+
# 校验子Agent所用模型是否有效,必要时回退到平台可用模型
|
148
180
|
try:
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
except Exception:
|
162
|
-
pass
|
163
|
-
if use_tools:
|
164
|
-
agent.set_use_tools(use_tools)
|
181
|
+
platform = getattr(agent, "model", None)
|
182
|
+
if platform:
|
183
|
+
available_models = platform.get_model_list()
|
184
|
+
if available_models:
|
185
|
+
available_names = [m for m, _ in available_models]
|
186
|
+
current_model_name = platform.name()
|
187
|
+
if current_model_name not in available_names:
|
188
|
+
PrettyOutput.print(
|
189
|
+
f"检测到子Agent模型 {current_model_name} 不存在于平台 {platform.platform_name()} 的可用模型列表,将回退到 {available_names[0]}",
|
190
|
+
OutputType.WARNING,
|
191
|
+
)
|
192
|
+
platform.set_model_name(available_names[0])
|
165
193
|
except Exception:
|
194
|
+
# 获取模型列表或设置模型失败时,保持原设置并继续,交由底层报错处理
|
166
195
|
pass
|
167
196
|
|
168
197
|
# 执行任务
|
@@ -8,12 +8,13 @@ sub_code_agent 工具
|
|
8
8
|
- 不依赖父 Agent,所有配置使用系统默认与全局变量
|
9
9
|
- 子Agent必须自动完成(auto_complete=True)且需要summary(need_summary=True)
|
10
10
|
"""
|
11
|
-
from typing import Any, Dict
|
11
|
+
from typing import Any, Dict
|
12
12
|
import json
|
13
13
|
|
14
14
|
from jarvis.jarvis_code_agent.code_agent import CodeAgent
|
15
15
|
from jarvis.jarvis_utils.globals import delete_agent
|
16
|
-
from jarvis.
|
16
|
+
from jarvis.jarvis_utils.config import set_config, get_git_check_mode
|
17
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
17
18
|
|
18
19
|
|
19
20
|
class SubCodeAgentTool:
|
@@ -59,11 +60,6 @@ class SubCodeAgentTool:
|
|
59
60
|
"stderr": "task 不能为空",
|
60
61
|
}
|
61
62
|
|
62
|
-
# 在模块级别打补丁,仅自动确认交互(允许用户输入)
|
63
|
-
def _auto_confirm(tip: str, default: bool = True) -> bool:
|
64
|
-
return default
|
65
|
-
|
66
|
-
code_agent_module.user_confirm = _auto_confirm
|
67
63
|
|
68
64
|
# 读取背景信息并组合任务
|
69
65
|
background: str = str(args.get("background", "")).strip()
|
@@ -131,7 +127,12 @@ class SubCodeAgentTool:
|
|
131
127
|
except Exception:
|
132
128
|
append_tools = None
|
133
129
|
|
130
|
+
# 在子Agent中放宽 Git 配置校验,避免因严格校验导致进程退出
|
131
|
+
# 使用配置项将校验模式临时切换为 warn,构造完成后恢复原值
|
132
|
+
old_mode = None
|
134
133
|
try:
|
134
|
+
old_mode = get_git_check_mode()
|
135
|
+
set_config("JARVIS_GIT_CHECK_MODE", "warn")
|
135
136
|
code_agent = CodeAgent(
|
136
137
|
model_group=model_group,
|
137
138
|
need_summary=True,
|
@@ -145,6 +146,12 @@ class SubCodeAgentTool:
|
|
145
146
|
"stdout": "",
|
146
147
|
"stderr": f"初始化 CodeAgent 失败(可能未配置 git 或当前非 git 仓库): {se}",
|
147
148
|
}
|
149
|
+
finally:
|
150
|
+
if old_mode is not None:
|
151
|
+
try:
|
152
|
+
set_config("JARVIS_GIT_CHECK_MODE", old_mode)
|
153
|
+
except Exception:
|
154
|
+
pass
|
148
155
|
|
149
156
|
# 子Agent需要自动完成
|
150
157
|
try:
|
@@ -165,6 +172,21 @@ class SubCodeAgentTool:
|
|
165
172
|
model_obj: Any = getattr(code_agent.agent, "model", None)
|
166
173
|
if model_obj is not None:
|
167
174
|
model_obj.set_model_name(parent_model_name)
|
175
|
+
# 模型有效性校验与回退,确保父Agent模型在子Agent平台上可用
|
176
|
+
try:
|
177
|
+
available_models = model_obj.get_model_list()
|
178
|
+
if available_models:
|
179
|
+
available_names = [m for m, _ in available_models]
|
180
|
+
current_model_name = model_obj.name()
|
181
|
+
if current_model_name not in available_names:
|
182
|
+
PrettyOutput.print(
|
183
|
+
f"检测到子CodeAgent模型 {current_model_name} 不存在于平台 {model_obj.platform_name()} 的可用模型列表,将回退到 {available_names[0]}",
|
184
|
+
OutputType.WARNING,
|
185
|
+
)
|
186
|
+
model_obj.set_model_name(available_names[0])
|
187
|
+
except Exception:
|
188
|
+
# 获取模型列表或设置模型失败时,保持原设置并继续,交由底层报错处理
|
189
|
+
pass
|
168
190
|
except Exception:
|
169
191
|
pass
|
170
192
|
except Exception:
|
@@ -7,25 +7,14 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
7
7
|
|
8
8
|
# 为了类型检查,总是导入这些模块
|
9
9
|
if TYPE_CHECKING:
|
10
|
-
|
11
|
-
import pty
|
12
|
-
import select
|
13
|
-
import signal
|
14
|
-
import subprocess
|
15
|
-
import threading
|
16
|
-
import queue
|
10
|
+
pass
|
17
11
|
|
18
12
|
# 平台相关的导入
|
19
13
|
if sys.platform != "win32":
|
20
|
-
|
21
|
-
import pty
|
22
|
-
import select
|
23
|
-
import signal
|
14
|
+
pass
|
24
15
|
else:
|
25
16
|
# Windows平台的导入
|
26
|
-
|
27
|
-
import threading
|
28
|
-
import queue
|
17
|
+
pass
|
29
18
|
|
30
19
|
|
31
20
|
class VirtualTTYTool:
|
@@ -31,25 +31,25 @@ arguments:
|
|
31
31
|
},
|
32
32
|
"FindRelatedFiles": {
|
33
33
|
"append": False,
|
34
|
-
"template":
|
34
|
+
"template": """
|
35
35
|
请使用工具在当前目录下查找与以下功能相关的文件:
|
36
36
|
""",
|
37
37
|
},
|
38
38
|
"Dev": {
|
39
39
|
"append": False,
|
40
|
-
"template":
|
40
|
+
"template": """
|
41
41
|
请调用create_code_agent开发以下需求:
|
42
42
|
""",
|
43
43
|
},
|
44
44
|
"Fix": {
|
45
45
|
"append": False,
|
46
|
-
"template":
|
46
|
+
"template": """
|
47
47
|
请修复以下问题:
|
48
48
|
""",
|
49
49
|
},
|
50
50
|
"Check": {
|
51
51
|
"append": True,
|
52
|
-
"template":
|
52
|
+
"template": """
|
53
53
|
请使用静态检查工具检查当前代码,必须严格遵守工具调用格式。
|
54
54
|
|
55
55
|
检查要求:
|
jarvis/jarvis_utils/config.py
CHANGED
@@ -130,9 +130,14 @@ def _get_resolved_model_config(
|
|
130
130
|
解析并合并模型配置,处理模型组。
|
131
131
|
|
132
132
|
优先级顺序:
|
133
|
-
|
134
|
-
|
135
|
-
|
133
|
+
- 当通过 model_group_override(例如命令行 -g/--llm-group)指定组时:
|
134
|
+
1. JARVIS_LLM_GROUP 中定义的组配置
|
135
|
+
2. 仅当组未提供对应键时,回退到顶层环境变量 (JARVIS_PLATFORM, JARVIS_MODEL, JARVIS_MAX_INPUT_TOKEN_COUNT)
|
136
|
+
3. 代码中的默认值
|
137
|
+
- 当未显式指定组时(使用默认组或未设置):
|
138
|
+
1. 顶层环境变量 (JARVIS_PLATFORM, JARVIS_MODEL, JARVIS_MAX_INPUT_TOKEN_COUNT)
|
139
|
+
2. JARVIS_LLM_GROUP 中定义的组配置
|
140
|
+
3. 代码中的默认值
|
136
141
|
|
137
142
|
返回:
|
138
143
|
Dict[str, Any]: 解析后的模型配置字典
|
@@ -155,14 +160,24 @@ def _get_resolved_model_config(
|
|
155
160
|
# Start with group config
|
156
161
|
resolved_config = group_config.copy()
|
157
162
|
|
158
|
-
#
|
159
|
-
|
163
|
+
# 覆盖策略:
|
164
|
+
# - 若通过 CLI 传入了 model_group_override,则优先使用组内配置;
|
165
|
+
# 仅当组未提供对应键时,才回落到顶层 GLOBAL_CONFIG_DATA。
|
166
|
+
# - 若未传入 override(即使用默认组),保持原有行为:由顶层键覆盖组配置。
|
167
|
+
override_keys = [
|
160
168
|
"JARVIS_PLATFORM",
|
161
169
|
"JARVIS_MODEL",
|
162
170
|
"JARVIS_MAX_INPUT_TOKEN_COUNT",
|
163
|
-
]
|
171
|
+
]
|
172
|
+
for key in override_keys:
|
164
173
|
if key in GLOBAL_CONFIG_DATA:
|
165
|
-
|
174
|
+
if model_group_override is None:
|
175
|
+
# 未显式指定组:顶层覆盖组
|
176
|
+
resolved_config[key] = GLOBAL_CONFIG_DATA[key]
|
177
|
+
else:
|
178
|
+
# 显式指定组:仅在组未定义该键时回退到顶层
|
179
|
+
if key not in resolved_config:
|
180
|
+
resolved_config[key] = GLOBAL_CONFIG_DATA[key]
|
166
181
|
|
167
182
|
return resolved_config
|
168
183
|
|
@@ -196,7 +211,7 @@ def _deprecated_platform_name_v1(model_group_override: Optional[str] = None) ->
|
|
196
211
|
返回:
|
197
212
|
str: 平台名称,默认为正常操作平台
|
198
213
|
"""
|
199
|
-
|
214
|
+
_get_resolved_model_config(model_group_override)
|
200
215
|
# Fallback to normal platform if thinking platform is not specified
|
201
216
|
return get_normal_platform_name(model_group_override)
|
202
217
|
|
@@ -208,7 +223,7 @@ def _deprecated_model_name_v1(model_group_override: Optional[str] = None) -> str
|
|
208
223
|
返回:
|
209
224
|
str: 模型名称,默认为正常操作模型
|
210
225
|
"""
|
211
|
-
|
226
|
+
_get_resolved_model_config(model_group_override)
|
212
227
|
# Fallback to normal model if thinking model is not specified
|
213
228
|
return get_normal_model_name(model_group_override)
|
214
229
|
|
@@ -220,7 +235,7 @@ def is_execute_tool_confirm() -> bool:
|
|
220
235
|
返回:
|
221
236
|
bool: 如果需要确认则返回True,默认为False
|
222
237
|
"""
|
223
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_EXECUTE_TOOL_CONFIRM", False)
|
238
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_EXECUTE_TOOL_CONFIRM", False)
|
224
239
|
|
225
240
|
|
226
241
|
def is_confirm_before_apply_patch() -> bool:
|
@@ -230,7 +245,7 @@ def is_confirm_before_apply_patch() -> bool:
|
|
230
245
|
返回:
|
231
246
|
bool: 如果需要确认则返回True,默认为False
|
232
247
|
"""
|
233
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_CONFIRM_BEFORE_APPLY_PATCH", False)
|
248
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_CONFIRM_BEFORE_APPLY_PATCH", False)
|
234
249
|
|
235
250
|
|
236
251
|
def get_data_dir() -> str:
|
@@ -270,7 +285,7 @@ def get_pretty_output() -> bool:
|
|
270
285
|
if platform.system() == "Windows":
|
271
286
|
return False
|
272
287
|
|
273
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_PRETTY_OUTPUT", False)
|
288
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_PRETTY_OUTPUT", False)
|
274
289
|
|
275
290
|
|
276
291
|
def is_use_methodology() -> bool:
|
@@ -280,7 +295,7 @@ def is_use_methodology() -> bool:
|
|
280
295
|
返回:
|
281
296
|
bool: 如果启用方法论则返回True,默认为True
|
282
297
|
"""
|
283
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_USE_METHODOLOGY", True)
|
298
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_USE_METHODOLOGY", True)
|
284
299
|
|
285
300
|
|
286
301
|
def is_use_analysis() -> bool:
|
@@ -290,7 +305,7 @@ def is_use_analysis() -> bool:
|
|
290
305
|
返回:
|
291
306
|
bool: 如果启用任务分析则返回True,默认为True
|
292
307
|
"""
|
293
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_USE_ANALYSIS", True)
|
308
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_USE_ANALYSIS", True)
|
294
309
|
|
295
310
|
|
296
311
|
def get_tool_load_dirs() -> List[str]:
|
@@ -390,7 +405,7 @@ def is_print_prompt() -> bool:
|
|
390
405
|
返回:
|
391
406
|
bool: 如果打印提示则返回True,默认为True
|
392
407
|
"""
|
393
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_PRINT_PROMPT", False)
|
408
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_PRINT_PROMPT", False)
|
394
409
|
|
395
410
|
|
396
411
|
def is_print_error_traceback() -> bool:
|
@@ -423,6 +438,20 @@ def is_enable_static_analysis() -> bool:
|
|
423
438
|
return GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_STATIC_ANALYSIS", True) is True
|
424
439
|
|
425
440
|
|
441
|
+
def get_git_check_mode() -> str:
|
442
|
+
"""
|
443
|
+
获取Git校验模式。
|
444
|
+
|
445
|
+
返回:
|
446
|
+
str: "strict" 或 "warn",默认为 "strict"
|
447
|
+
"""
|
448
|
+
mode = GLOBAL_CONFIG_DATA.get("JARVIS_GIT_CHECK_MODE", "strict")
|
449
|
+
try:
|
450
|
+
return str(mode)
|
451
|
+
except Exception:
|
452
|
+
return "strict"
|
453
|
+
|
454
|
+
|
426
455
|
def get_mcp_config() -> List[Dict[str, Any]]:
|
427
456
|
"""
|
428
457
|
获取MCP配置列表。
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""FZF selector utility."""
|
3
|
+
import shutil
|
4
|
+
import subprocess
|
5
|
+
from typing import List, Optional, Union
|
6
|
+
|
7
|
+
def fzf_select(
|
8
|
+
options: Union[List[str], List[dict]],
|
9
|
+
prompt: str = "SELECT> ",
|
10
|
+
key: Optional[str] = None,
|
11
|
+
) -> Optional[str]:
|
12
|
+
"""
|
13
|
+
Uses fzf to select an item from a list.
|
14
|
+
|
15
|
+
Args:
|
16
|
+
options: A list of strings or dicts to choose from.
|
17
|
+
prompt: The prompt to display in fzf.
|
18
|
+
key: If options is a list of dicts, this is the key to display.
|
19
|
+
|
20
|
+
Returns:
|
21
|
+
The selected item, or None if fzf is not available or the selection is cancelled.
|
22
|
+
"""
|
23
|
+
if shutil.which("fzf") is None:
|
24
|
+
return None
|
25
|
+
|
26
|
+
if not options:
|
27
|
+
return None
|
28
|
+
|
29
|
+
if isinstance(options[0], dict):
|
30
|
+
if key is None:
|
31
|
+
raise ValueError("A key must be provided for a list of dicts.")
|
32
|
+
input_lines = [str(item.get(key, "")) for item in options]
|
33
|
+
else:
|
34
|
+
input_lines = [str(item) for item in options]
|
35
|
+
|
36
|
+
try:
|
37
|
+
process = subprocess.run(
|
38
|
+
[
|
39
|
+
"fzf",
|
40
|
+
"--prompt",
|
41
|
+
prompt,
|
42
|
+
"--height",
|
43
|
+
"40%",
|
44
|
+
"--border",
|
45
|
+
"--layout=reverse",
|
46
|
+
],
|
47
|
+
input="\n".join(input_lines),
|
48
|
+
stdout=subprocess.PIPE,
|
49
|
+
stderr=subprocess.PIPE,
|
50
|
+
text=True,
|
51
|
+
check=True,
|
52
|
+
)
|
53
|
+
selected = process.stdout.strip()
|
54
|
+
return selected if selected else None
|
55
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
56
|
+
return None
|
jarvis/jarvis_utils/git_utils.py
CHANGED
jarvis/jarvis_utils/globals.py
CHANGED