auto-coder 0.1.334__py3-none-any.whl → 0.1.340__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 auto-coder might be problematic. Click here for more details.
- {auto_coder-0.1.334.dist-info → auto_coder-0.1.340.dist-info}/METADATA +2 -2
- {auto_coder-0.1.334.dist-info → auto_coder-0.1.340.dist-info}/RECORD +70 -34
- autocoder/agent/agentic_edit.py +833 -0
- autocoder/agent/agentic_edit_tools/__init__.py +28 -0
- autocoder/agent/agentic_edit_tools/ask_followup_question_tool_resolver.py +32 -0
- autocoder/agent/agentic_edit_tools/attempt_completion_tool_resolver.py +29 -0
- autocoder/agent/agentic_edit_tools/base_tool_resolver.py +29 -0
- autocoder/agent/agentic_edit_tools/execute_command_tool_resolver.py +84 -0
- autocoder/agent/agentic_edit_tools/list_code_definition_names_tool_resolver.py +75 -0
- autocoder/agent/agentic_edit_tools/list_files_tool_resolver.py +62 -0
- autocoder/agent/agentic_edit_tools/plan_mode_respond_tool_resolver.py +30 -0
- autocoder/agent/agentic_edit_tools/read_file_tool_resolver.py +36 -0
- autocoder/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +95 -0
- autocoder/agent/agentic_edit_tools/search_files_tool_resolver.py +70 -0
- autocoder/agent/agentic_edit_tools/use_mcp_tool_resolver.py +55 -0
- autocoder/agent/agentic_edit_tools/write_to_file_tool_resolver.py +98 -0
- autocoder/agent/agentic_edit_types.py +124 -0
- autocoder/agent/agentic_filter.py +14 -7
- autocoder/auto_coder.py +39 -18
- autocoder/auto_coder_rag.py +18 -9
- autocoder/auto_coder_runner.py +107 -8
- autocoder/chat_auto_coder.py +1 -2
- autocoder/chat_auto_coder_lang.py +18 -2
- autocoder/commands/tools.py +5 -1
- autocoder/common/__init__.py +2 -0
- autocoder/common/auto_coder_lang.py +84 -8
- autocoder/common/code_auto_generate_diff.py +1 -1
- autocoder/common/code_auto_generate_editblock.py +1 -1
- autocoder/common/code_auto_generate_strict_diff.py +1 -1
- autocoder/common/mcp_hub.py +185 -2
- autocoder/common/mcp_server.py +243 -306
- autocoder/common/mcp_server_install.py +269 -0
- autocoder/common/mcp_server_types.py +169 -0
- autocoder/common/stream_out_type.py +3 -0
- autocoder/common/v2/agent/__init__.py +0 -0
- autocoder/common/v2/agent/agentic_edit.py +1433 -0
- autocoder/common/v2/agent/agentic_edit_conversation.py +179 -0
- autocoder/common/v2/agent/agentic_edit_tools/__init__.py +28 -0
- autocoder/common/v2/agent/agentic_edit_tools/ask_followup_question_tool_resolver.py +70 -0
- autocoder/common/v2/agent/agentic_edit_tools/attempt_completion_tool_resolver.py +35 -0
- autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +33 -0
- autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +88 -0
- autocoder/common/v2/agent/agentic_edit_tools/list_code_definition_names_tool_resolver.py +80 -0
- autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +105 -0
- autocoder/common/v2/agent/agentic_edit_tools/plan_mode_respond_tool_resolver.py +35 -0
- autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +51 -0
- autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +153 -0
- autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +104 -0
- autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +46 -0
- autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +58 -0
- autocoder/common/v2/agent/agentic_edit_types.py +167 -0
- autocoder/common/v2/agent/agentic_tool_display.py +184 -0
- autocoder/common/v2/code_agentic_editblock_manager.py +812 -0
- autocoder/common/v2/code_auto_generate.py +1 -1
- autocoder/common/v2/code_auto_generate_diff.py +1 -1
- autocoder/common/v2/code_auto_generate_editblock.py +1 -1
- autocoder/common/v2/code_auto_generate_strict_diff.py +1 -1
- autocoder/common/v2/code_editblock_manager.py +151 -178
- autocoder/compilers/provided_compiler.py +3 -2
- autocoder/events/event_manager.py +4 -4
- autocoder/events/event_types.py +1 -0
- autocoder/memory/active_context_manager.py +2 -29
- autocoder/models.py +10 -2
- autocoder/shadows/shadow_manager.py +1 -1
- autocoder/utils/llms.py +4 -2
- autocoder/version.py +1 -1
- {auto_coder-0.1.334.dist-info → auto_coder-0.1.340.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.334.dist-info → auto_coder-0.1.340.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.334.dist-info → auto_coder-0.1.340.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.334.dist-info → auto_coder-0.1.340.dist-info}/top_level.txt +0 -0
autocoder/auto_coder_runner.py
CHANGED
|
@@ -22,6 +22,8 @@ from autocoder.common.result_manager import ResultManager
|
|
|
22
22
|
from autocoder.version import __version__
|
|
23
23
|
from autocoder.auto_coder import main as auto_coder_main
|
|
24
24
|
from autocoder.utils import get_last_yaml_file
|
|
25
|
+
from autocoder.commands.auto_command import CommandAutoTuner, AutoCommandRequest, CommandConfig, MemoryConfig
|
|
26
|
+
from autocoder.common.v2.agent.agentic_edit import AgenticEdit,AgenticEditRequest
|
|
25
27
|
from autocoder.index.symbols_utils import (
|
|
26
28
|
extract_symbols,
|
|
27
29
|
SymbolType,
|
|
@@ -40,7 +42,11 @@ import git
|
|
|
40
42
|
from autocoder.common import git_utils
|
|
41
43
|
from autocoder.chat_auto_coder_lang import get_message
|
|
42
44
|
from autocoder.agent.auto_guess_query import AutoGuessQuery
|
|
43
|
-
from autocoder.common.mcp_server import get_mcp_server
|
|
45
|
+
from autocoder.common.mcp_server import get_mcp_server
|
|
46
|
+
from autocoder.common.mcp_server_types import (
|
|
47
|
+
McpRequest, McpInstallRequest, McpRemoveRequest, McpListRequest,
|
|
48
|
+
McpListRunningRequest, McpRefreshRequest, McpServerInfoRequest
|
|
49
|
+
)
|
|
44
50
|
import byzerllm
|
|
45
51
|
from byzerllm.utils import format_str_jinja2
|
|
46
52
|
from autocoder.common.memory_manager import get_global_memory_file_paths
|
|
@@ -54,11 +60,12 @@ from autocoder.memory.active_context_manager import ActiveContextManager
|
|
|
54
60
|
from autocoder.common.command_completer import CommandCompleter,FileSystemModel as CCFileSystemModel,MemoryConfig as CCMemoryModel
|
|
55
61
|
from autocoder.common.conf_validator import ConfigValidator
|
|
56
62
|
from autocoder import command_parser as CommandParser
|
|
57
|
-
from loguru import logger
|
|
63
|
+
from loguru import logger as global_logger
|
|
58
64
|
from autocoder.utils.project_structure import EnhancedFileAnalyzer
|
|
65
|
+
from autocoder.common import SourceCodeList,SourceCode
|
|
59
66
|
|
|
60
|
-
## 对外API,用于第三方集成 auto-coder 使用。
|
|
61
67
|
|
|
68
|
+
## 对外API,用于第三方集成 auto-coder 使用。
|
|
62
69
|
class SymbolItem(BaseModel):
|
|
63
70
|
symbol_name: str
|
|
64
71
|
symbol_type: SymbolType
|
|
@@ -218,6 +225,36 @@ def get_all_extensions(directory: str = ".") -> str:
|
|
|
218
225
|
# 转换为逗号分隔的字符串
|
|
219
226
|
return ",".join(sorted(all_extensions))
|
|
220
227
|
|
|
228
|
+
def configure_logger():
|
|
229
|
+
# 设置日志目录和文件
|
|
230
|
+
log_dir = os.path.join(project_root, ".auto-coder", "logs")
|
|
231
|
+
os.makedirs(log_dir, exist_ok=True)
|
|
232
|
+
log_file = os.path.join(log_dir, "auto-coder.log")
|
|
233
|
+
|
|
234
|
+
# 配置全局日志
|
|
235
|
+
# 默认情况下,所有日志都写入文件
|
|
236
|
+
# 控制台上默认不输出任何日志,除非显式配置
|
|
237
|
+
global_logger.configure(
|
|
238
|
+
handlers=[
|
|
239
|
+
{
|
|
240
|
+
"sink": log_file,
|
|
241
|
+
"level": "INFO",
|
|
242
|
+
"rotation": "10 MB",
|
|
243
|
+
"retention": "1 week",
|
|
244
|
+
"format": "{time:YYYY-MM-DD HH:mm:ss} | {level} | {name} | {message}",
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
"sink": sys.stdout,
|
|
248
|
+
"level": "INFO",
|
|
249
|
+
"format": "{time:YYYY-MM-DD HH:mm:ss} | {name} | {message}",
|
|
250
|
+
# 默认不打印任何日志到控制台
|
|
251
|
+
"filter": lambda record: False
|
|
252
|
+
}
|
|
253
|
+
]
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
configure_logger()
|
|
257
|
+
|
|
221
258
|
def initialize_system(args:InitializeSystemRequest):
|
|
222
259
|
from autocoder.utils.model_provider_selector import ModelProviderSelector
|
|
223
260
|
from autocoder import models as models_module
|
|
@@ -2742,12 +2779,74 @@ def conf_import(path: str):
|
|
|
2742
2779
|
from autocoder.common.conf_import_export import import_conf
|
|
2743
2780
|
import_conf(os.getcwd(), path)
|
|
2744
2781
|
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
""
|
|
2748
|
-
|
|
2749
|
-
|
|
2782
|
+
def generate_new_yaml(query: str):
|
|
2783
|
+
memory = get_memory()
|
|
2784
|
+
conf = memory.get("conf",{})
|
|
2785
|
+
current_files = memory.get("current_files",{}).get("files",[])
|
|
2786
|
+
auto_coder_main(["next", "chat_action"])
|
|
2787
|
+
latest_yaml_file = get_last_yaml_file("actions")
|
|
2788
|
+
if latest_yaml_file:
|
|
2789
|
+
yaml_config = {
|
|
2790
|
+
"include_file": ["./base/base.yml"],
|
|
2791
|
+
"auto_merge": conf.get("auto_merge", "editblock"),
|
|
2792
|
+
"human_as_model": conf.get("human_as_model", "false") == "true",
|
|
2793
|
+
"skip_build_index": conf.get("skip_build_index", "true") == "true",
|
|
2794
|
+
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
|
2795
|
+
"silence": conf.get("silence", "true") == "true",
|
|
2796
|
+
"include_project_structure": conf.get("include_project_structure", "true")
|
|
2797
|
+
== "true",
|
|
2798
|
+
"exclude_files": memory.get("exclude_files", []),
|
|
2799
|
+
}
|
|
2800
|
+
yaml_config["context"] = ""
|
|
2801
|
+
for key, value in conf.items():
|
|
2802
|
+
converted_value = convert_config_value(key, value)
|
|
2803
|
+
if converted_value is not None:
|
|
2804
|
+
yaml_config[key] = converted_value
|
|
2805
|
+
|
|
2806
|
+
yaml_config["urls"] = current_files + get_llm_friendly_package_docs(
|
|
2807
|
+
return_paths=True
|
|
2808
|
+
)
|
|
2809
|
+
# handle image
|
|
2810
|
+
v = Image.convert_image_paths_from(query)
|
|
2811
|
+
yaml_config["query"] = v
|
|
2812
|
+
|
|
2813
|
+
yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
|
|
2750
2814
|
|
|
2815
|
+
execute_file = os.path.join("actions", latest_yaml_file)
|
|
2816
|
+
with open(os.path.join(execute_file), "w",encoding="utf-8") as f:
|
|
2817
|
+
f.write(yaml_content)
|
|
2818
|
+
return execute_file,convert_yaml_to_config(execute_file)
|
|
2819
|
+
|
|
2820
|
+
@run_in_raw_thread()
|
|
2821
|
+
def auto_command(query: str,extra_args: Dict[str,Any]={}):
|
|
2822
|
+
"""处理/auto指令"""
|
|
2823
|
+
args = get_final_config()
|
|
2824
|
+
memory = get_memory()
|
|
2825
|
+
if args.enable_agentic_edit:
|
|
2826
|
+
from autocoder.run_context import get_run_context,RunMode
|
|
2827
|
+
execute_file,args = generate_new_yaml(query)
|
|
2828
|
+
args.file = execute_file
|
|
2829
|
+
current_files = memory.get("current_files",{}).get("files",[])
|
|
2830
|
+
sources = []
|
|
2831
|
+
for file in current_files:
|
|
2832
|
+
with open(file,"r",encoding="utf-8") as f:
|
|
2833
|
+
sources.append(SourceCode(module_name=file,source_code=f.read()))
|
|
2834
|
+
|
|
2835
|
+
llm = get_single_llm(args.code_model or args.model,product_mode=args.product_mode)
|
|
2836
|
+
conversation_history = extra_args.get("conversations",[])
|
|
2837
|
+
agent = AgenticEdit(llm=llm,args=args,files=SourceCodeList(sources=sources),
|
|
2838
|
+
conversation_history=conversation_history,
|
|
2839
|
+
memory_config=MemoryConfig(memory=memory,
|
|
2840
|
+
save_memory_func=save_memory), command_config=CommandConfig,
|
|
2841
|
+
conversation_name="current"
|
|
2842
|
+
)
|
|
2843
|
+
if get_run_context() == RunMode.TERMINAL:
|
|
2844
|
+
agent.run_in_terminal(AgenticEditRequest(user_input=query))
|
|
2845
|
+
else:
|
|
2846
|
+
agent.run_with_events(AgenticEditRequest(user_input=query))
|
|
2847
|
+
return
|
|
2848
|
+
|
|
2849
|
+
args = get_final_config()
|
|
2751
2850
|
# 准备请求参数
|
|
2752
2851
|
request = AutoCommandRequest(
|
|
2753
2852
|
user_input=query
|
autocoder/chat_auto_coder.py
CHANGED
|
@@ -30,6 +30,14 @@ MESSAGES = {
|
|
|
30
30
|
"en": "Available builtin MCP servers:",
|
|
31
31
|
"zh": "可用的内置 MCP 服务器:"
|
|
32
32
|
},
|
|
33
|
+
"mcp_list_external_title": {
|
|
34
|
+
"en": "Available external MCP servers:",
|
|
35
|
+
"zh": "可用的外部 MCP 服务器:"
|
|
36
|
+
},
|
|
37
|
+
"mcp_list_marketplace_title": {
|
|
38
|
+
"en": "Available marketplace MCP servers:",
|
|
39
|
+
"zh": "可用的市场 MCP 服务器:"
|
|
40
|
+
},
|
|
33
41
|
"mcp_refresh_error": {
|
|
34
42
|
"en": "Error refreshing MCP servers: {{error}}",
|
|
35
43
|
"zh": "刷新 MCP 服务器时出错:{{error}}"
|
|
@@ -543,8 +551,8 @@ MESSAGES = {
|
|
|
543
551
|
"zh": "用法: /plugins <命令>\n可用的子命令:\n /plugins /list - 列出所有可用插件\n /plugins /load <名称> - 加载一个插件\n /plugins /unload <名称> - 卸载一个插件\n /plugins/dirs - 列出插件目录\n /plugins/dirs /add <路径> - 添加一个插件目录\n /plugins/dirs /remove <路径> - 移除一个插件目录\n /plugins/dirs /clear - 清除所有插件目录"
|
|
544
552
|
},
|
|
545
553
|
"mcp_server_info_error": {
|
|
546
|
-
"en": "Error getting MCP server info: {{
|
|
547
|
-
"zh": "获取MCP
|
|
554
|
+
"en": "Error getting MCP server info: {{error}}",
|
|
555
|
+
"zh": "获取 MCP 服务器信息时出错:{{error}}"
|
|
548
556
|
},
|
|
549
557
|
"mcp_server_info_title": {
|
|
550
558
|
"en": "Connected MCP Server Info",
|
|
@@ -553,6 +561,14 @@ MESSAGES = {
|
|
|
553
561
|
"active_context_desc": {
|
|
554
562
|
"en": "Manage active context tasks, list all tasks and their status",
|
|
555
563
|
"zh": "管理活动上下文任务,列出所有任务及其状态"
|
|
564
|
+
},
|
|
565
|
+
"marketplace_add_success": {
|
|
566
|
+
"en": "Successfully added marketplace item: {{name}}",
|
|
567
|
+
"zh": "成功添加市场项目:{{name}}"
|
|
568
|
+
},
|
|
569
|
+
"marketplace_add_error": {
|
|
570
|
+
"en": "Error adding marketplace item: {{name}} - {{error}}",
|
|
571
|
+
"zh": "添加市场项目时出错:{{name}} - {{error}}"
|
|
556
572
|
}
|
|
557
573
|
}
|
|
558
574
|
|
autocoder/commands/tools.py
CHANGED
|
@@ -42,6 +42,11 @@ from autocoder.events.event_manager_singleton import get_event_manager
|
|
|
42
42
|
from autocoder.events import event_content as EventContentCreator
|
|
43
43
|
from autocoder.linters.linter_factory import LinterFactory, lint_file, lint_project, format_lint_result
|
|
44
44
|
import traceback
|
|
45
|
+
from autocoder.common.mcp_server import get_mcp_server
|
|
46
|
+
from autocoder.common.mcp_server_types import (
|
|
47
|
+
McpRequest, McpInstallRequest, McpRemoveRequest, McpListRequest,
|
|
48
|
+
McpListRunningRequest, McpRefreshRequest
|
|
49
|
+
)
|
|
45
50
|
|
|
46
51
|
|
|
47
52
|
@byzerllm.prompt()
|
|
@@ -76,7 +81,6 @@ class AutoCommandTools:
|
|
|
76
81
|
self.printer = Printer()
|
|
77
82
|
|
|
78
83
|
def execute_mcp_server(self, query: str) -> str:
|
|
79
|
-
from autocoder.common.mcp_server import get_mcp_server, McpRequest, McpInstallRequest, McpRemoveRequest, McpListRequest, McpListRunningRequest, McpRefreshRequest
|
|
80
84
|
mcp_server = get_mcp_server()
|
|
81
85
|
response = mcp_server.send_request(
|
|
82
86
|
McpRequest(
|
autocoder/common/__init__.py
CHANGED
|
@@ -272,6 +272,7 @@ class AutoCoderArgs(pydantic.BaseModel):
|
|
|
272
272
|
index_model_anti_quota_limit: Optional[int] = 0
|
|
273
273
|
|
|
274
274
|
enable_agentic_filter: Optional[bool] = False
|
|
275
|
+
enable_agentic_edit: Optional[bool] = False
|
|
275
276
|
|
|
276
277
|
|
|
277
278
|
index_filter_level: Optional[int] = 0
|
|
@@ -416,6 +417,7 @@ class AutoCoderArgs(pydantic.BaseModel):
|
|
|
416
417
|
event_file: Optional[str] = None
|
|
417
418
|
|
|
418
419
|
enable_active_context: Optional[bool] = False
|
|
420
|
+
enable_active_context_in_generate: Optional[bool] = False
|
|
419
421
|
|
|
420
422
|
generate_max_rounds: Optional[int] = 5
|
|
421
423
|
|
|
@@ -453,7 +453,7 @@ MESSAGES = {
|
|
|
453
453
|
"quick_filter_too_long": {
|
|
454
454
|
"en": "⚠️ index file is too large ({{ tokens_len }}/{{ max_tokens }}). The query will be split into {{ split_size }} chunks.",
|
|
455
455
|
"zh": "⚠️ 索引文件过大 ({{ tokens_len }}/{{ max_tokens }})。查询将被分成 {{ split_size }} 个部分执行。"
|
|
456
|
-
},
|
|
456
|
+
},
|
|
457
457
|
"quick_filter_tokens_len": {
|
|
458
458
|
"en": "📊 Current index size: {{ tokens_len }} tokens",
|
|
459
459
|
"zh": "📊 当前索引大小: {{ tokens_len }} tokens"
|
|
@@ -787,16 +787,92 @@ MESSAGES = {
|
|
|
787
787
|
"zh": "已达到最大未合并代码块修复尝试次数"
|
|
788
788
|
},
|
|
789
789
|
"agenticFilterContext": {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
790
|
+
"en": "Start to find context...",
|
|
791
|
+
"zh": "开始智能查找上下文...."
|
|
792
|
+
},
|
|
793
|
+
"agenticFilterContextFinished": {
|
|
794
|
+
"en": "End to find context...",
|
|
795
|
+
"zh": "结束智能查找上下文...."
|
|
796
|
+
},
|
|
797
|
+
"/context/check/start":{
|
|
798
|
+
"en": "Starting missing context checking process.",
|
|
799
|
+
"zh": "开始缺失上下文检查过程."
|
|
800
|
+
},
|
|
801
|
+
"/context/check/end": {
|
|
802
|
+
"en": "Finished missing context checking process.",
|
|
803
|
+
"zh": "结束缺失上下文检查过程."
|
|
804
|
+
},
|
|
805
|
+
"/unmerged_blocks/check/start": {
|
|
806
|
+
"en": "Starting unmerged blocks checking process.",
|
|
807
|
+
"zh": "开始未合并代码检查过程."
|
|
808
|
+
},
|
|
809
|
+
"/unmerged_blocks/check/end": {
|
|
810
|
+
"en": "Finished unmerged blocks checking process.",
|
|
811
|
+
"zh": "结束未合并代码检查过程."
|
|
812
|
+
},
|
|
813
|
+
"/lint/check/start": {
|
|
814
|
+
"en": "Starting lint error checking process.",
|
|
815
|
+
"zh": "开始代码质量检查过程."
|
|
816
|
+
},
|
|
817
|
+
"/lint/check/end": {
|
|
818
|
+
"en": "Finished lint error checking process.",
|
|
819
|
+
"zh": "结束代码质量检查过程."
|
|
820
|
+
},
|
|
821
|
+
"/compile/check/start": {
|
|
822
|
+
"en": "Starting compile error checking process.",
|
|
823
|
+
"zh": "开始编译错误检查过程."
|
|
824
|
+
},
|
|
825
|
+
"/compile/check/end": {
|
|
826
|
+
"en": "Finished compile error checking process.",
|
|
827
|
+
"zh": "结束编译错误检查过程."
|
|
828
|
+
},
|
|
829
|
+
"/agent/edit/objective":{
|
|
830
|
+
"en":"Objective",
|
|
831
|
+
"zh":"目标"
|
|
832
|
+
},
|
|
833
|
+
"/agent/edit/user_query":{
|
|
834
|
+
"en":"User Query",
|
|
835
|
+
"zh":"用户查询"
|
|
836
|
+
}
|
|
797
837
|
}
|
|
798
838
|
|
|
799
839
|
|
|
840
|
+
# 新增 ReplaceInFileToolResolver 国际化消息
|
|
841
|
+
MESSAGES.update({
|
|
842
|
+
"replace_in_file.access_denied": {
|
|
843
|
+
"en": "Error: Access denied. Attempted to modify file outside the project directory: {{file_path}}",
|
|
844
|
+
"zh": "错误:拒绝访问。尝试修改项目目录之外的文件:{{file_path}}"
|
|
845
|
+
},
|
|
846
|
+
"replace_in_file.file_not_found": {
|
|
847
|
+
"en": "Error: File not found at path: {{file_path}}",
|
|
848
|
+
"zh": "错误:未找到文件路径:{{file_path}}"
|
|
849
|
+
},
|
|
850
|
+
"replace_in_file.read_error": {
|
|
851
|
+
"en": "An error occurred while reading the file for replacement: {{error}}",
|
|
852
|
+
"zh": "读取待替换文件时发生错误:{{error}}"
|
|
853
|
+
},
|
|
854
|
+
"replace_in_file.no_valid_blocks": {
|
|
855
|
+
"en": "Error: No valid SEARCH/REPLACE blocks found in the provided diff.",
|
|
856
|
+
"zh": "错误:在提供的diff中未找到有效的SEARCH/REPLACE代码块。"
|
|
857
|
+
},
|
|
858
|
+
"replace_in_file.apply_failed": {
|
|
859
|
+
"en": "Failed to apply any changes. Errors:\n{{errors}}",
|
|
860
|
+
"zh": "未能应用任何更改。错误信息:\n{{errors}}"
|
|
861
|
+
},
|
|
862
|
+
"replace_in_file.apply_success": {
|
|
863
|
+
"en": "Successfully applied {{applied}}/{{total}} changes to file: {{file_path}}.",
|
|
864
|
+
"zh": "成功应用了 {{applied}}/{{total}} 个更改到文件:{{file_path}}。"
|
|
865
|
+
},
|
|
866
|
+
"replace_in_file.apply_success_with_warnings": {
|
|
867
|
+
"en": "Successfully applied {{applied}}/{{total}} changes to file: {{file_path}}.\nWarnings:\n{{errors}}",
|
|
868
|
+
"zh": "成功应用了 {{applied}}/{{total}} 个更改到文件:{{file_path}}。\n警告信息:\n{{errors}}"
|
|
869
|
+
},
|
|
870
|
+
"replace_in_file.write_error": {
|
|
871
|
+
"en": "An error occurred while writing the modified file: {{error}}",
|
|
872
|
+
"zh": "写入修改后的文件时发生错误:{{error}}"
|
|
873
|
+
}
|
|
874
|
+
})
|
|
875
|
+
|
|
800
876
|
def get_system_language():
|
|
801
877
|
try:
|
|
802
878
|
return locale.getdefaultlocale()[0][:2]
|
|
@@ -329,7 +329,7 @@ class CodeAutoGenerateDiff:
|
|
|
329
329
|
# 获取包上下文信息
|
|
330
330
|
package_context = ""
|
|
331
331
|
|
|
332
|
-
if self.args.enable_active_context:
|
|
332
|
+
if self.args.enable_active_context and self.args.enable_active_context_in_generate:
|
|
333
333
|
# 初始化活动上下文管理器
|
|
334
334
|
active_context_manager = ActiveContextManager(self.llm, self.args.source_dir)
|
|
335
335
|
# 获取活动上下文信息
|
|
@@ -438,7 +438,7 @@ class CodeAutoGenerateEditBlock:
|
|
|
438
438
|
# 获取包上下文信息
|
|
439
439
|
package_context = ""
|
|
440
440
|
|
|
441
|
-
if self.args.enable_active_context:
|
|
441
|
+
if self.args.enable_active_context and self.args.enable_active_context_in_generate:
|
|
442
442
|
# 获取活动上下文信息
|
|
443
443
|
result = active_context_manager.load_active_contexts_for_files(
|
|
444
444
|
[source.module_name for source in source_code_list.sources]
|
|
@@ -299,7 +299,7 @@ class CodeAutoGenerateStrictDiff:
|
|
|
299
299
|
# 获取包上下文信息
|
|
300
300
|
package_context = ""
|
|
301
301
|
|
|
302
|
-
if self.args.enable_active_context:
|
|
302
|
+
if self.args.enable_active_context and self.args.enable_active_context_in_generate:
|
|
303
303
|
# 初始化活动上下文管理器
|
|
304
304
|
active_context_manager = ActiveContextManager(self.llm, self.args.source_dir)
|
|
305
305
|
# 获取活动上下文信息
|
autocoder/common/mcp_hub.py
CHANGED
|
@@ -13,6 +13,7 @@ from pydantic import BaseModel, Field
|
|
|
13
13
|
from loguru import logger
|
|
14
14
|
from contextlib import AsyncExitStack
|
|
15
15
|
from datetime import timedelta
|
|
16
|
+
from autocoder.common.mcp_server_types import MarketplaceMCPServerItem
|
|
16
17
|
|
|
17
18
|
try:
|
|
18
19
|
from mcp import ClientSession
|
|
@@ -42,7 +43,6 @@ class McpResource(BaseModel):
|
|
|
42
43
|
description: Optional[str] = None
|
|
43
44
|
mime_type: Optional[str] = None
|
|
44
45
|
|
|
45
|
-
|
|
46
46
|
class McpResourceTemplate(BaseModel):
|
|
47
47
|
"""Represents an MCP resource template"""
|
|
48
48
|
|
|
@@ -133,7 +133,7 @@ class McpHub:
|
|
|
133
133
|
cls._instance._initialized = False
|
|
134
134
|
return cls._instance
|
|
135
135
|
|
|
136
|
-
def __init__(self, settings_path: Optional[str] = None):
|
|
136
|
+
def __init__(self, settings_path: Optional[str] = None, marketplace_path: Optional[str] = None):
|
|
137
137
|
if self._initialized:
|
|
138
138
|
return
|
|
139
139
|
"""Initialize the MCP Hub with a path to settings file"""
|
|
@@ -141,6 +141,12 @@ class McpHub:
|
|
|
141
141
|
self.settings_path = Path.home() / ".auto-coder" / "mcp" / "settings.json"
|
|
142
142
|
else:
|
|
143
143
|
self.settings_path = Path(settings_path)
|
|
144
|
+
|
|
145
|
+
if marketplace_path is None:
|
|
146
|
+
self.marketplace_path = Path.home() / ".auto-coder" / "mcp" / "marketplace.json"
|
|
147
|
+
else:
|
|
148
|
+
self.marketplace_path = Path(marketplace_path)
|
|
149
|
+
|
|
144
150
|
self.connections: Dict[str, McpConnection] = {}
|
|
145
151
|
self.is_connecting = False
|
|
146
152
|
self.exit_stacks: Dict[str, AsyncExitStack] = {}
|
|
@@ -149,6 +155,11 @@ class McpHub:
|
|
|
149
155
|
self.settings_path.parent.mkdir(parents=True, exist_ok=True)
|
|
150
156
|
if not self.settings_path.exists():
|
|
151
157
|
self._write_default_settings()
|
|
158
|
+
|
|
159
|
+
# Ensure marketplace file exists
|
|
160
|
+
self.marketplace_path.parent.mkdir(parents=True, exist_ok=True)
|
|
161
|
+
if not self.marketplace_path.exists():
|
|
162
|
+
self._write_default_marketplace()
|
|
152
163
|
|
|
153
164
|
self._initialized = True
|
|
154
165
|
|
|
@@ -157,6 +168,178 @@ class McpHub:
|
|
|
157
168
|
default_settings = {"mcpServers": {}}
|
|
158
169
|
with open(self.settings_path, "w", encoding="utf-8") as f:
|
|
159
170
|
json.dump(default_settings, f, indent=2)
|
|
171
|
+
|
|
172
|
+
def _write_default_marketplace(self):
|
|
173
|
+
"""Write default marketplace file"""
|
|
174
|
+
default_marketplace = {"mcpServers": []}
|
|
175
|
+
with open(self.marketplace_path, "w", encoding="utf-8") as f:
|
|
176
|
+
json.dump(default_marketplace, f, indent=2)
|
|
177
|
+
|
|
178
|
+
def _read_marketplace(self) -> Dict[str, List[Dict[str, Any]]]:
|
|
179
|
+
"""Read marketplace file"""
|
|
180
|
+
try:
|
|
181
|
+
with open(self.marketplace_path,"r", encoding="utf-8") as f:
|
|
182
|
+
return json.load(f)
|
|
183
|
+
except Exception as e:
|
|
184
|
+
logger.error(f"Failed to read marketplace: {e}")
|
|
185
|
+
return {"mcpServers": []}
|
|
186
|
+
|
|
187
|
+
def get_marketplace_items(self) -> List[MarketplaceMCPServerItem]:
|
|
188
|
+
"""Get all marketplace items"""
|
|
189
|
+
data = self._read_marketplace()
|
|
190
|
+
return [MarketplaceMCPServerItem(**item) for item in data.get("mcpServers", [])]
|
|
191
|
+
|
|
192
|
+
def get_marketplace_item(self, name: str) -> Optional[MarketplaceMCPServerItem]:
|
|
193
|
+
"""Get a marketplace item by name"""
|
|
194
|
+
items = self.get_marketplace_items()
|
|
195
|
+
for item in items:
|
|
196
|
+
if item.name == name:
|
|
197
|
+
return item
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
async def add_marketplace_item(self, item: MarketplaceMCPServerItem) -> bool:
|
|
201
|
+
"""
|
|
202
|
+
Add a new marketplace item
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
item: MarketplaceMCPServerItem to add
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
bool: True if successful, False otherwise
|
|
209
|
+
"""
|
|
210
|
+
try:
|
|
211
|
+
# Check if item with this name already exists
|
|
212
|
+
existing = self.get_marketplace_item(item.name)
|
|
213
|
+
if existing:
|
|
214
|
+
logger.warning(f"Marketplace item with name {item.name} already exists")
|
|
215
|
+
return False
|
|
216
|
+
|
|
217
|
+
# Add the new item
|
|
218
|
+
data = self._read_marketplace()
|
|
219
|
+
data["mcpServers"].append(item.dict())
|
|
220
|
+
|
|
221
|
+
# Write back to file
|
|
222
|
+
with open(self.marketplace_path, "w", encoding="utf-8") as f:
|
|
223
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
224
|
+
|
|
225
|
+
logger.info(f"Added marketplace item: {item.name}")
|
|
226
|
+
return True
|
|
227
|
+
except Exception as e:
|
|
228
|
+
logger.error(f"Failed to add marketplace item: {e}")
|
|
229
|
+
return False
|
|
230
|
+
|
|
231
|
+
async def update_marketplace_item(self, name: str, updated_item: MarketplaceMCPServerItem) -> bool:
|
|
232
|
+
"""
|
|
233
|
+
Update an existing marketplace item
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
name: Name of the item to update
|
|
237
|
+
updated_item: Updated MarketplaceMCPServerItem
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
bool: True if successful, False otherwise
|
|
241
|
+
"""
|
|
242
|
+
try:
|
|
243
|
+
data = self._read_marketplace()
|
|
244
|
+
items = data.get("mcpServers", [])
|
|
245
|
+
|
|
246
|
+
# Find the item to update
|
|
247
|
+
for i, item in enumerate(items):
|
|
248
|
+
if item.get("name") == name:
|
|
249
|
+
# Update the item
|
|
250
|
+
items[i] = updated_item.model_dump()
|
|
251
|
+
|
|
252
|
+
# Write back to file
|
|
253
|
+
with open(self.marketplace_path, "w", encoding="utf-8") as f:
|
|
254
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
255
|
+
|
|
256
|
+
logger.info(f"Updated marketplace item: {name}")
|
|
257
|
+
return True
|
|
258
|
+
|
|
259
|
+
logger.warning(f"Marketplace item with name {name} not found")
|
|
260
|
+
return False
|
|
261
|
+
except Exception as e:
|
|
262
|
+
logger.error(f"Failed to update marketplace item: {e}")
|
|
263
|
+
return False
|
|
264
|
+
|
|
265
|
+
async def remove_marketplace_item(self, name: str) -> bool:
|
|
266
|
+
"""
|
|
267
|
+
Remove a marketplace item
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
name: Name of the item to remove
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
bool: True if successful, False otherwise
|
|
274
|
+
"""
|
|
275
|
+
try:
|
|
276
|
+
data = self._read_marketplace()
|
|
277
|
+
items = data.get("mcpServers", [])
|
|
278
|
+
|
|
279
|
+
# Find and remove the item
|
|
280
|
+
for i, item in enumerate(items):
|
|
281
|
+
if item.get("name") == name:
|
|
282
|
+
del items[i]
|
|
283
|
+
|
|
284
|
+
# Write back to file
|
|
285
|
+
with open(self.marketplace_path, "w", encoding="utf-8") as f:
|
|
286
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
287
|
+
|
|
288
|
+
logger.info(f"Removed marketplace item: {name}")
|
|
289
|
+
return True
|
|
290
|
+
|
|
291
|
+
logger.warning(f"Marketplace item with name {name} not found")
|
|
292
|
+
return False
|
|
293
|
+
except Exception as e:
|
|
294
|
+
logger.error(f"Failed to remove marketplace item: {e}")
|
|
295
|
+
return False
|
|
296
|
+
|
|
297
|
+
async def apply_marketplace_item(self, name: str) -> bool:
|
|
298
|
+
"""
|
|
299
|
+
Apply a marketplace item to server config
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
name: Name of the item to apply
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
bool: True if successful, False otherwise
|
|
306
|
+
"""
|
|
307
|
+
try:
|
|
308
|
+
item = self.get_marketplace_item(name)
|
|
309
|
+
if not item:
|
|
310
|
+
logger.warning(f"Marketplace item with name {name} not found")
|
|
311
|
+
return False
|
|
312
|
+
|
|
313
|
+
# Convert marketplace item to server config
|
|
314
|
+
config = {}
|
|
315
|
+
|
|
316
|
+
if item.mcp_type == "command":
|
|
317
|
+
config = {
|
|
318
|
+
"command": item.command,
|
|
319
|
+
"args": item.args,
|
|
320
|
+
"env": item.env,
|
|
321
|
+
"transport": {
|
|
322
|
+
"type": "stdio",
|
|
323
|
+
"endpoint": ""
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
elif item.mcp_type == "sse":
|
|
327
|
+
config = {
|
|
328
|
+
"transport": {
|
|
329
|
+
"type": "sse",
|
|
330
|
+
"endpoint": item.url
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
else:
|
|
334
|
+
logger.error(f"Unknown MCP type: {item.mcp_type}")
|
|
335
|
+
return False
|
|
336
|
+
|
|
337
|
+
# Add server config
|
|
338
|
+
result = await self.add_server_config(name, config)
|
|
339
|
+
return result
|
|
340
|
+
except Exception as e:
|
|
341
|
+
logger.error(f"Failed to apply marketplace item: {e}")
|
|
342
|
+
return False
|
|
160
343
|
|
|
161
344
|
async def add_server_config(self, name: str, config: Dict[str, Any]) -> None:
|
|
162
345
|
"""
|