jarvis-ai-assistant 0.3.27__py3-none-any.whl → 0.3.29__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 +73 -29
- jarvis/jarvis_agent/agent_manager.py +6 -0
- jarvis/jarvis_agent/config_editor.py +1 -1
- jarvis/jarvis_agent/event_bus.py +2 -2
- jarvis/jarvis_agent/events.py +157 -0
- jarvis/jarvis_agent/file_methodology_manager.py +18 -7
- jarvis/jarvis_agent/jarvis.py +11 -4
- jarvis/jarvis_agent/memory_manager.py +4 -4
- jarvis/jarvis_agent/prompts.py +2 -2
- jarvis/jarvis_agent/protocols.py +4 -1
- jarvis/jarvis_agent/run_loop.py +9 -24
- jarvis/jarvis_agent/shell_input_handler.py +7 -2
- jarvis/jarvis_agent/task_analyzer.py +19 -15
- jarvis/jarvis_agent/task_manager.py +6 -4
- jarvis/jarvis_agent/user_interaction.py +1 -1
- jarvis/jarvis_agent/utils.py +50 -0
- jarvis/jarvis_code_agent/code_agent.py +2 -2
- jarvis/jarvis_code_analysis/code_review.py +0 -1
- jarvis/jarvis_git_utils/git_commiter.py +13 -4
- jarvis/jarvis_mcp/sse_mcp_client.py +1 -1
- jarvis/jarvis_mcp/stdio_mcp_client.py +1 -1
- jarvis/jarvis_memory_organizer/memory_organizer.py +6 -9
- jarvis/jarvis_methodology/main.py +0 -2
- jarvis/jarvis_multi_agent/__init__.py +3 -3
- jarvis/jarvis_platform/base.py +1 -1
- jarvis/jarvis_platform/kimi.py +1 -1
- jarvis/jarvis_platform/registry.py +1 -1
- jarvis/jarvis_platform/tongyi.py +1 -1
- jarvis/jarvis_platform/yuanbao.py +1 -2
- 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_rag/retriever.py +3 -3
- jarvis/jarvis_smart_shell/main.py +0 -1
- jarvis/jarvis_stats/cli.py +2 -3
- jarvis/jarvis_stats/stats.py +3 -4
- jarvis/jarvis_stats/storage.py +3 -3
- jarvis/jarvis_tools/clear_memory.py +1 -3
- jarvis/jarvis_tools/cli/main.py +0 -1
- jarvis/jarvis_tools/edit_file.py +3 -4
- jarvis/jarvis_tools/execute_script.py +2 -2
- jarvis/jarvis_tools/generate_new_tool.py +3 -5
- jarvis/jarvis_tools/registry.py +2 -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 +21 -2
- jarvis/jarvis_tools/sub_code_agent.py +18 -2
- jarvis/jarvis_tools/virtual_tty.py +3 -14
- jarvis/jarvis_utils/builtin_replace_map.py +4 -4
- jarvis/jarvis_utils/config.py +32 -17
- jarvis/jarvis_utils/fzf.py +4 -3
- jarvis/jarvis_utils/git_utils.py +1 -1
- jarvis/jarvis_utils/globals.py +1 -2
- jarvis/jarvis_utils/input.py +5 -5
- jarvis/jarvis_utils/methodology.py +3 -5
- jarvis/jarvis_utils/output.py +1 -1
- jarvis/jarvis_utils/utils.py +160 -31
- {jarvis_ai_assistant-0.3.27.dist-info → jarvis_ai_assistant-0.3.29.dist-info}/METADATA +1 -1
- {jarvis_ai_assistant-0.3.27.dist-info → jarvis_ai_assistant-0.3.29.dist-info}/RECORD +66 -64
- {jarvis_ai_assistant-0.3.27.dist-info → jarvis_ai_assistant-0.3.29.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.3.27.dist-info → jarvis_ai_assistant-0.3.29.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.3.27.dist-info → jarvis_ai_assistant-0.3.29.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.27.dist-info → jarvis_ai_assistant-0.3.29.dist-info}/top_level.txt +0 -0
jarvis/jarvis_stats/stats.py
CHANGED
@@ -167,7 +167,6 @@ class StatsManager:
|
|
167
167
|
"""
|
168
168
|
# 处理时间范围
|
169
169
|
# 当未提供时间过滤参数时,默认显示全历史数据
|
170
|
-
all_time = False
|
171
170
|
if last_hours or last_days:
|
172
171
|
if end_time is None:
|
173
172
|
end_time = datetime.now()
|
@@ -177,7 +176,7 @@ class StatsManager:
|
|
177
176
|
elif last_days:
|
178
177
|
start_time = end_time - timedelta(days=last_days)
|
179
178
|
else:
|
180
|
-
|
179
|
+
pass
|
181
180
|
|
182
181
|
if metric_name is None:
|
183
182
|
# 显示所有指标摘要
|
@@ -605,8 +604,8 @@ class StatsManager:
|
|
605
604
|
|
606
605
|
@staticmethod
|
607
606
|
def _show_multiple_charts(
|
608
|
-
start_time: datetime,
|
609
|
-
end_time: datetime,
|
607
|
+
start_time: Optional[datetime],
|
608
|
+
end_time: Optional[datetime],
|
610
609
|
aggregation: str,
|
611
610
|
tags: Optional[Dict[str, str]],
|
612
611
|
width: Optional[int] = None,
|
jarvis/jarvis_stats/storage.py
CHANGED
@@ -8,7 +8,7 @@ import json
|
|
8
8
|
import os
|
9
9
|
from datetime import datetime, timedelta
|
10
10
|
from pathlib import Path
|
11
|
-
from typing import Dict, List, Optional, Any
|
11
|
+
from typing import Dict, List, Optional, Any, Set
|
12
12
|
from collections import defaultdict
|
13
13
|
import sys
|
14
14
|
import time
|
@@ -457,7 +457,7 @@ class StatsStorage:
|
|
457
457
|
metrics_from_meta = set(meta.get("metrics", {}).keys())
|
458
458
|
|
459
459
|
# 扫描所有数据文件获取实际存在的指标
|
460
|
-
metrics_from_data:
|
460
|
+
metrics_from_data: Set[str] = set()
|
461
461
|
for data_file in self.data_dir.glob("stats_*.json"):
|
462
462
|
try:
|
463
463
|
data = self._load_json(data_file)
|
@@ -467,7 +467,7 @@ class StatsStorage:
|
|
467
467
|
continue
|
468
468
|
|
469
469
|
# 扫描总量缓存目录中已有的指标文件
|
470
|
-
metrics_from_totals:
|
470
|
+
metrics_from_totals: Set[str] = set()
|
471
471
|
try:
|
472
472
|
for f in self.totals_dir.glob("*"):
|
473
473
|
if f.is_file():
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
import json
|
3
|
-
import shutil
|
4
3
|
from pathlib import Path
|
5
4
|
from typing import Any, Dict, List, Optional
|
6
5
|
|
@@ -8,7 +7,6 @@ from jarvis.jarvis_utils.config import get_data_dir
|
|
8
7
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
9
8
|
from jarvis.jarvis_utils.globals import (
|
10
9
|
clear_short_term_memories,
|
11
|
-
get_short_term_memories,
|
12
10
|
short_term_memories,
|
13
11
|
)
|
14
12
|
|
@@ -212,7 +210,7 @@ class ClearMemoryTool:
|
|
212
210
|
# 生成结果报告
|
213
211
|
|
214
212
|
# 详细报告
|
215
|
-
report =
|
213
|
+
report = "# 记忆清除报告\n\n"
|
216
214
|
report += f"**总计清除**: {total_removed} 条记忆\n\n"
|
217
215
|
|
218
216
|
if tags:
|
jarvis/jarvis_tools/cli/main.py
CHANGED
jarvis/jarvis_tools/edit_file.py
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
- 完善的错误处理和回滚机制
|
15
15
|
- 严格的格式保持要求
|
16
16
|
"""
|
17
|
-
from typing import Any, Dict
|
17
|
+
from typing import Any, Dict, List
|
18
18
|
|
19
19
|
from jarvis.jarvis_agent.edit_file_handler import EditFileHandler
|
20
20
|
|
@@ -122,8 +122,7 @@ class FileSearchReplaceTool:
|
|
122
122
|
|
123
123
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
124
124
|
|
125
|
-
stdout_messages:
|
126
|
-
stderr_messages: list[str] = []
|
125
|
+
stdout_messages: List[str] = []
|
127
126
|
overall_success = False
|
128
127
|
file_results = []
|
129
128
|
|
@@ -168,7 +167,7 @@ class FileSearchReplaceTool:
|
|
168
167
|
)
|
169
168
|
|
170
169
|
# 整合所有错误信息到stderr
|
171
|
-
all_stderr:
|
170
|
+
all_stderr: List[str] = []
|
172
171
|
for file_result in file_results:
|
173
172
|
if not file_result["success"]:
|
174
173
|
all_stderr.append(f"文件 {file_result['file']} 处理失败: {file_result['stderr']}")
|
@@ -2,7 +2,7 @@
|
|
2
2
|
import os
|
3
3
|
import tempfile
|
4
4
|
from pathlib import Path
|
5
|
-
from typing import Any, Dict
|
5
|
+
from typing import Any, Dict, List
|
6
6
|
|
7
7
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
8
8
|
|
@@ -74,7 +74,7 @@ class ScriptTool:
|
|
74
74
|
stream.feed(data)
|
75
75
|
|
76
76
|
# 清理每行右侧空格,并过滤空行
|
77
|
-
cleaned:
|
77
|
+
cleaned: List[str] = []
|
78
78
|
for y in range(screen.lines):
|
79
79
|
line = screen.buffer[y]
|
80
80
|
stripped = "".join(char.data for char in line.values()).rstrip()
|
@@ -120,15 +120,13 @@ class generate_new_tool:
|
|
120
120
|
# 注册新工具到当前的工具注册表
|
121
121
|
success_message = f"工具 '{tool_name}' 已成功生成在 {tool_file_path}"
|
122
122
|
|
123
|
-
registration_successful = False
|
124
123
|
if agent:
|
125
124
|
tool_registry = agent.get_tool_registry()
|
126
125
|
if tool_registry:
|
127
126
|
# 尝试加载并注册新工具
|
128
127
|
|
129
128
|
if tool_registry.register_tool_by_file(str(tool_file_path)):
|
130
|
-
success_message +=
|
131
|
-
registration_successful = True
|
129
|
+
success_message += "\n已成功注册到当前会话的工具注册表中"
|
132
130
|
else:
|
133
131
|
# 注册失败,删除已创建的文件
|
134
132
|
PrettyOutput.print(
|
@@ -140,13 +138,13 @@ class generate_new_tool:
|
|
140
138
|
return {
|
141
139
|
"success": False,
|
142
140
|
"stdout": "",
|
143
|
-
"stderr":
|
141
|
+
"stderr": "工具文件已生成,但注册失败。文件已被删除。",
|
144
142
|
}
|
145
143
|
else:
|
146
144
|
PrettyOutput.print(
|
147
145
|
"未找到工具注册表,无法自动注册工具", OutputType.WARNING
|
148
146
|
)
|
149
|
-
success_message +=
|
147
|
+
success_message += "\n注册到当前会话失败,可能需要重新启动Jarvis"
|
150
148
|
|
151
149
|
# 检查并安装缺失的依赖
|
152
150
|
try:
|
jarvis/jarvis_tools/registry.py
CHANGED
@@ -15,7 +15,6 @@ from jarvis.jarvis_mcp.stdio_mcp_client import StdioMcpClient
|
|
15
15
|
from jarvis.jarvis_mcp.streamable_mcp_client import StreamableMcpClient
|
16
16
|
from jarvis.jarvis_tools.base import Tool
|
17
17
|
from jarvis.jarvis_utils.config import get_data_dir, get_tool_load_dirs
|
18
|
-
from jarvis.jarvis_utils.input import user_confirm
|
19
18
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
20
19
|
from jarvis.jarvis_utils.tag import ct, ot
|
21
20
|
from jarvis.jarvis_utils.utils import is_context_overflow, daily_check_git_updates
|
@@ -128,7 +127,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
128
127
|
"""加载工具"""
|
129
128
|
tools = self.get_all_tools()
|
130
129
|
if tools:
|
131
|
-
tools_prompt =
|
130
|
+
tools_prompt = "<tools_section>\n"
|
132
131
|
tools_prompt += " <header>## 可用工具:</header>\n"
|
133
132
|
tools_prompt += " <tools_list>\n"
|
134
133
|
for tool in tools:
|
@@ -202,7 +201,7 @@ class ToolRegistry(OutputHandlerProtocol):
|
|
202
201
|
def _get_tool_stats(self) -> Dict[str, int]:
|
203
202
|
"""从数据目录获取工具调用统计"""
|
204
203
|
from jarvis.jarvis_stats.stats import StatsManager
|
205
|
-
from datetime import datetime
|
204
|
+
from datetime import datetime
|
206
205
|
|
207
206
|
# 获取所有工具的统计数据
|
208
207
|
tool_stats = {}
|
@@ -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
@@ -8,12 +8,13 @@ sub_agent 工具
|
|
8
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, List
|
12
12
|
import json
|
13
13
|
|
14
14
|
from jarvis.jarvis_agent import Agent
|
15
15
|
from jarvis.jarvis_utils.globals import delete_agent
|
16
16
|
from jarvis.jarvis_tools.registry import ToolRegistry
|
17
|
+
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
17
18
|
|
18
19
|
|
19
20
|
class SubAgentTool:
|
@@ -106,7 +107,7 @@ class SubAgentTool:
|
|
106
107
|
|
107
108
|
# 解析可用工具列表(支持数组或以逗号分隔的字符串)
|
108
109
|
_use_tools = args.get("use_tools", None)
|
109
|
-
use_tools:
|
110
|
+
use_tools: List[str] = []
|
110
111
|
if isinstance(_use_tools, list):
|
111
112
|
use_tools = [str(x).strip() for x in _use_tools if str(x).strip()]
|
112
113
|
elif isinstance(_use_tools, str):
|
@@ -175,6 +176,24 @@ class SubAgentTool:
|
|
175
176
|
except Exception:
|
176
177
|
pass
|
177
178
|
|
179
|
+
# 校验子Agent所用模型是否有效,必要时回退到平台可用模型
|
180
|
+
try:
|
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])
|
193
|
+
except Exception:
|
194
|
+
# 获取模型列表或设置模型失败时,保持原设置并继续,交由底层报错处理
|
195
|
+
pass
|
196
|
+
|
178
197
|
# 执行任务
|
179
198
|
result = agent.run(enhanced_task)
|
180
199
|
|
@@ -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, List
|
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
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:
|
@@ -84,7 +85,7 @@ class SubCodeAgentTool:
|
|
84
85
|
except Exception:
|
85
86
|
parent_agent = None
|
86
87
|
model_group = None
|
87
|
-
use_tools:
|
88
|
+
use_tools: List[str] = []
|
88
89
|
try:
|
89
90
|
if parent_agent is not None:
|
90
91
|
if getattr(parent_agent, "model", None):
|
@@ -171,6 +172,21 @@ class SubCodeAgentTool:
|
|
171
172
|
model_obj: Any = getattr(code_agent.agent, "model", None)
|
172
173
|
if model_obj is not None:
|
173
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
|
174
190
|
except Exception:
|
175
191
|
pass
|
176
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",
|
288
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_PRETTY_OUTPUT", True)
|
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:
|
@@ -408,9 +423,9 @@ def is_force_save_memory() -> bool:
|
|
408
423
|
获取是否强制保存记忆。
|
409
424
|
|
410
425
|
返回:
|
411
|
-
bool: 如果强制保存记忆则返回True,默认为
|
426
|
+
bool: 如果强制保存记忆则返回True,默认为False
|
412
427
|
"""
|
413
|
-
return GLOBAL_CONFIG_DATA.get("JARVIS_FORCE_SAVE_MEMORY",
|
428
|
+
return GLOBAL_CONFIG_DATA.get("JARVIS_FORCE_SAVE_MEMORY", False) is True
|
414
429
|
|
415
430
|
|
416
431
|
def is_enable_static_analysis() -> bool:
|
jarvis/jarvis_utils/fzf.py
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
"""FZF selector utility."""
|
3
3
|
import shutil
|
4
4
|
import subprocess
|
5
|
-
from typing import List, Optional, Union
|
5
|
+
from typing import List, Optional, Union, Dict, Any, cast
|
6
6
|
|
7
7
|
def fzf_select(
|
8
|
-
options: Union[List[str], List[
|
8
|
+
options: Union[List[str], List[Dict[str, Any]]],
|
9
9
|
prompt: str = "SELECT> ",
|
10
10
|
key: Optional[str] = None,
|
11
11
|
) -> Optional[str]:
|
@@ -29,7 +29,8 @@ def fzf_select(
|
|
29
29
|
if isinstance(options[0], dict):
|
30
30
|
if key is None:
|
31
31
|
raise ValueError("A key must be provided for a list of dicts.")
|
32
|
-
|
32
|
+
options_dict = cast(List[Dict[str, Any]], options)
|
33
|
+
input_lines = [str(item.get(key, "")) for item in options_dict]
|
33
34
|
else:
|
34
35
|
input_lines = [str(item) for item in options]
|
35
36
|
|
jarvis/jarvis_utils/git_utils.py
CHANGED
jarvis/jarvis_utils/globals.py
CHANGED
jarvis/jarvis_utils/input.py
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
import os
|
12
12
|
import sys
|
13
13
|
import base64
|
14
|
-
from typing import Iterable, List
|
14
|
+
from typing import Iterable, List, Optional
|
15
15
|
import wcwidth
|
16
16
|
|
17
17
|
from colorama import Fore
|
@@ -308,7 +308,7 @@ class FileCompleter(Completer):
|
|
308
308
|
import os as _os
|
309
309
|
|
310
310
|
if self._all_files_cache is None:
|
311
|
-
files:
|
311
|
+
files: List[str] = []
|
312
312
|
for root, dirs, fnames in _os.walk(".", followlinks=False):
|
313
313
|
# Exclude .git directory
|
314
314
|
dirs[:] = [d for d in dirs if d != ".git"]
|
@@ -429,7 +429,7 @@ def _show_history_and_copy():
|
|
429
429
|
|
430
430
|
|
431
431
|
def _get_multiline_input_internal(
|
432
|
-
tip: str, preset: str
|
432
|
+
tip: str, preset: Optional[str] = None, preset_cursor: Optional[int] = None
|
433
433
|
) -> str:
|
434
434
|
"""
|
435
435
|
Internal function to get multiline input using prompt_toolkit.
|
@@ -660,8 +660,8 @@ def get_multiline_input(tip: str, print_on_empty: bool = True) -> str:
|
|
660
660
|
tip: 提示文本,将显示在底部工具栏中
|
661
661
|
print_on_empty: 当输入为空字符串时,是否打印“输入已取消”提示。默认打印。
|
662
662
|
"""
|
663
|
-
preset: str
|
664
|
-
preset_cursor: int
|
663
|
+
preset: Optional[str] = None
|
664
|
+
preset_cursor: Optional[int] = None
|
665
665
|
while True:
|
666
666
|
user_input = _get_multiline_input_internal(
|
667
667
|
tip, preset=preset, preset_cursor=preset_cursor
|
@@ -10,7 +10,6 @@
|
|
10
10
|
import json
|
11
11
|
import os
|
12
12
|
import tempfile
|
13
|
-
from pathlib import Path
|
14
13
|
from typing import Any, Dict, List, Optional
|
15
14
|
|
16
15
|
from jarvis.jarvis_platform.base import BasePlatform
|
@@ -21,9 +20,8 @@ from jarvis.jarvis_utils.config import (
|
|
21
20
|
get_central_methodology_repo,
|
22
21
|
get_max_input_token_count,
|
23
22
|
)
|
24
|
-
from jarvis.jarvis_utils.globals import get_agent, current_agent_name
|
25
23
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
26
|
-
from jarvis.jarvis_utils.utils import
|
24
|
+
from jarvis.jarvis_utils.utils import daily_check_git_updates
|
27
25
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
28
26
|
|
29
27
|
|
@@ -234,7 +232,7 @@ def load_methodology(
|
|
234
232
|
methodology_titles = list(methodologies.keys())
|
235
233
|
|
236
234
|
# 步骤2:让大模型选择相关性高的方法论
|
237
|
-
selection_prompt =
|
235
|
+
selection_prompt = """以下是所有可用的方法论标题:
|
238
236
|
|
239
237
|
"""
|
240
238
|
for i, title in enumerate(methodology_titles, 1):
|
@@ -305,7 +303,7 @@ def load_methodology(
|
|
305
303
|
|
306
304
|
# 步骤3:将选择出来的方法论内容提供给大模型生成步骤
|
307
305
|
# 首先构建基础提示词部分
|
308
|
-
base_prompt =
|
306
|
+
base_prompt = """以下是与用户需求相关的方法论内容:
|
309
307
|
|
310
308
|
"""
|
311
309
|
suffix_prompt = f"""以下是所有可用的工具内容:
|