auto-coder 0.1.389__py3-none-any.whl → 0.1.390__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.389.dist-info → auto_coder-0.1.390.dist-info}/METADATA +2 -2
- {auto_coder-0.1.389.dist-info → auto_coder-0.1.390.dist-info}/RECORD +18 -14
- autocoder/auto_coder_rag.py +5 -0
- autocoder/auto_coder_runner.py +12 -3
- autocoder/chat_auto_coder.py +6 -2
- autocoder/common/__init__.py +1 -0
- autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +16 -17
- autocoder/memory/__init__.py +0 -7
- autocoder/memory/active_changes.py +255 -0
- autocoder/memory/active_diagrams.py +302 -0
- autocoder/memory/active_documents.py +287 -0
- autocoder/memory/active_header.py +88 -0
- autocoder/memory/active_package.py +109 -365
- autocoder/version.py +1 -1
- {auto_coder-0.1.389.dist-info → auto_coder-0.1.390.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.389.dist-info → auto_coder-0.1.390.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.389.dist-info → auto_coder-0.1.390.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.389.dist-info → auto_coder-0.1.390.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: auto-coder
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.390
|
|
4
4
|
Summary: AutoCoder: AutoCoder
|
|
5
5
|
Author: allwefantasy
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -28,7 +28,7 @@ Requires-Dist: prompt-toolkit
|
|
|
28
28
|
Requires-Dist: tokenizers
|
|
29
29
|
Requires-Dist: aiofiles
|
|
30
30
|
Requires-Dist: readerwriterlock
|
|
31
|
-
Requires-Dist: byzerllm[saas] >=0.1.
|
|
31
|
+
Requires-Dist: byzerllm[saas] >=0.1.188
|
|
32
32
|
Requires-Dist: patch
|
|
33
33
|
Requires-Dist: diff-match-patch
|
|
34
34
|
Requires-Dist: GitPython
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
autocoder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
autocoder/auto_coder.py,sha256=7602L3tG0JErNxh8vkLAmGUgv2c-DGPzPCkmWIQt9bs,69757
|
|
3
|
-
autocoder/auto_coder_rag.py,sha256=
|
|
4
|
-
autocoder/auto_coder_runner.py,sha256=
|
|
3
|
+
autocoder/auto_coder_rag.py,sha256=9PeW7m1bdZx9Q4yw6ULeBKuJQ2EZyO2MepTofl9RxA4,41376
|
|
4
|
+
autocoder/auto_coder_runner.py,sha256=3kjlxvCgnOd-_P7VqPVcBYU_xqTdW515c-XFwuXUgdI,115789
|
|
5
5
|
autocoder/auto_coder_server.py,sha256=bLORGEclcVdbBVfM140JCI8WtdrU0jbgqdJIVVupiEU,20578
|
|
6
6
|
autocoder/benchmark.py,sha256=Ypomkdzd1T3GE6dRICY3Hj547dZ6_inqJbBJIp5QMco,4423
|
|
7
|
-
autocoder/chat_auto_coder.py,sha256=
|
|
7
|
+
autocoder/chat_auto_coder.py,sha256=atlHr3kh9jiVoMt5Wa69_shxRxLjLMrFyz-Iw605g1E,26772
|
|
8
8
|
autocoder/chat_auto_coder_lang.py,sha256=ylLr1GskchU6kIUJY2TiznrBg-ckc1o-8fDsKZZ0iQU,29337
|
|
9
9
|
autocoder/command_args.py,sha256=HxflngkYtTrV17Vfgk6lyUyiG68jP2ftSc7FYr9AXwY,30585
|
|
10
10
|
autocoder/command_parser.py,sha256=fx1g9E6GaM273lGTcJqaFQ-hoksS_Ik2glBMnVltPCE,10013
|
|
11
11
|
autocoder/lang.py,sha256=PFtATuOhHRnfpqHQkXr6p4C893JvpsgwTMif3l-GEi0,14321
|
|
12
12
|
autocoder/models.py,sha256=pD5u6gcMKRwWaLxeVin18g25k-ERyeHOFsRpOgO_Ae0,13788
|
|
13
13
|
autocoder/run_context.py,sha256=IUfSO6_gp2Wt1blFWAmOpN0b0nDrTTk4LmtCYUBIoro,1643
|
|
14
|
-
autocoder/version.py,sha256=
|
|
14
|
+
autocoder/version.py,sha256=cPqQwif1FlW0StEITphmOzbZ77p-tnWBHct7dK_j2hs,25
|
|
15
15
|
autocoder/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
autocoder/agent/agentic_filter.py,sha256=zlInIRhawKIYTJjCiJBWqPCOV5UtMbh5VnvszfTy2vo,39824
|
|
17
17
|
autocoder/agent/auto_demand_organizer.py,sha256=URAq0gSEiHeV_W4zwhOI_83kHz0Ryfj1gcfh5jwCv_w,6501
|
|
@@ -60,7 +60,7 @@ autocoder/commands/auto_web.py,sha256=K0Gv7lil5UqmExr_sAJNOcwNxw_q1vhvre1jjQ7tA3
|
|
|
60
60
|
autocoder/commands/tools.py,sha256=IX_zx5mWAvQDED7wUHTqNtrCmLNo9ztFV1aZ6AflY4o,34292
|
|
61
61
|
autocoder/common/JupyterClient.py,sha256=O-wi6pXeAEYhAY24kDa0BINrLYvKS6rKyWe98pDClS0,2816
|
|
62
62
|
autocoder/common/ShellClient.py,sha256=fM1q8t_XMSbLBl2zkCNC2J9xuyKN3eXzGm6hHhqL2WY,2286
|
|
63
|
-
autocoder/common/__init__.py,sha256=
|
|
63
|
+
autocoder/common/__init__.py,sha256=QjsPwSx3cjQzfC3i_Wk6eFMIQal1tj1ENI4Gs7TmZIg,14943
|
|
64
64
|
autocoder/common/action_yml_file_manager.py,sha256=DdF5P1R_B_chCnnqoA2IgogakWLZk_nItiJZUfX0_Wo,17857
|
|
65
65
|
autocoder/common/anything2images.py,sha256=0ILBbWzY02M-CiWB-vzuomb_J1hVdxRcenAfIrAXq9M,25283
|
|
66
66
|
autocoder/common/anything2img.py,sha256=iZQmg8srXlD7N5uGl5b_ONKJMBjYoW8kPmokkG6ISF0,10118
|
|
@@ -182,7 +182,7 @@ autocoder/common/v2/agent/agentic_edit_tools/__init__.py,sha256=RbPZZcZg_VnGssL5
|
|
|
182
182
|
autocoder/common/v2/agent/agentic_edit_tools/ask_followup_question_tool_resolver.py,sha256=-HFXo3RR6CH8xXjDaE2mYV4XasTLAmvXe6WutL7qbwA,3208
|
|
183
183
|
autocoder/common/v2/agent/agentic_edit_tools/attempt_completion_tool_resolver.py,sha256=82ZGKeRBSDKeead_XVBW4FxpiE-5dS7tBOk_3RZ6B5s,1511
|
|
184
184
|
autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py,sha256=Zid2m1uZd-2wVFGc_n_KAViXZyNjbdLSpI5n7ut1RUQ,1036
|
|
185
|
-
autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py,sha256=
|
|
185
|
+
autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py,sha256=vXkmNLNaNDWrDHCHMl0UVtDyThXvk1V32BkWqhQny9E,5570
|
|
186
186
|
autocoder/common/v2/agent/agentic_edit_tools/list_code_definition_names_tool_resolver.py,sha256=8QoMsADUDWliqiDt_dpguz31403syB8eeW0Pcw-qfb8,3842
|
|
187
187
|
autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py,sha256=1tJX9RYRU0zRjKZMzFlZzKm-4R32CzRnZ0UQJj4pxAk,8074
|
|
188
188
|
autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py,sha256=dIdV12VuczHpHuHgx2B1j_3BZYc9PL0jfHCuBk9ryk8,2005
|
|
@@ -248,9 +248,13 @@ autocoder/linters/test_python_linter.py,sha256=zYPliyjm1s0IJmlIadyWQedsLNOGbaz7Q
|
|
|
248
248
|
autocoder/linters/test_reactjs_linter.py,sha256=72VnejikldyEH5PdvJzrgtcxhnlGkVZTe3hWRGnw4mA,7099
|
|
249
249
|
autocoder/linters/test_vue_linter.py,sha256=m031brPZdK66Yi-hvlPvL0RYyQxvY43lHu_ATVxrvQs,7592
|
|
250
250
|
autocoder/linters/vue_linter.py,sha256=MjF-SgSbgOucyv0hnp2r56CIfe8hqDibs0NKnvUUvLw,21225
|
|
251
|
-
autocoder/memory/__init__.py,sha256=
|
|
251
|
+
autocoder/memory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
252
|
+
autocoder/memory/active_changes.py,sha256=I2CWMdw-rUqEOcJX-8apk5in4y2gomWhaufytkqQOsY,9492
|
|
252
253
|
autocoder/memory/active_context_manager.py,sha256=nqWD4lBLNcskXDRERhPpqnmn_i1V7_CTfQSN3xAX6b8,32297
|
|
253
|
-
autocoder/memory/
|
|
254
|
+
autocoder/memory/active_diagrams.py,sha256=4_JRyzLZeXvLyopWY35oHI9omnXWhRZITmpazltn7NA,11055
|
|
255
|
+
autocoder/memory/active_documents.py,sha256=QEfssXWPWvl4pWeZuv7ZEUx0Ynm-VRPRrFJIwmP4wAA,10060
|
|
256
|
+
autocoder/memory/active_header.py,sha256=_6ZXe0uixqc24SUXmnsVzIZYHU6Y3fV5hIU56zFlWko,3092
|
|
257
|
+
autocoder/memory/active_package.py,sha256=LMRAeI4--tURHbGn2Xb4rdeTTFyRcnruAL7utHpfTtI,16183
|
|
254
258
|
autocoder/memory/async_processor.py,sha256=htHzLGupw9IHQAEdLe2AEaALZSItPi3AltDt8FMTRHk,4643
|
|
255
259
|
autocoder/memory/directory_mapper.py,sha256=BXHblOdRpeZb7URDECALp9uN5oi91KmkW9g_UaWFuZY,2513
|
|
256
260
|
autocoder/plugins/__init__.py,sha256=T71wGXBP24NhFyf9BntKDXWPIvKp5hWhq_-xK7C-ptE,43722
|
|
@@ -336,9 +340,9 @@ autocoder/utils/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
336
340
|
autocoder/utils/auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
337
341
|
autocoder/utils/auto_coder_utils/chat_stream_out.py,sha256=t902pKxQ5xM7zgIHiAOsTPLwxhE6VuvXAqPy751S7fg,14096
|
|
338
342
|
autocoder/utils/chat_auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
339
|
-
auto_coder-0.1.
|
|
340
|
-
auto_coder-0.1.
|
|
341
|
-
auto_coder-0.1.
|
|
342
|
-
auto_coder-0.1.
|
|
343
|
-
auto_coder-0.1.
|
|
344
|
-
auto_coder-0.1.
|
|
343
|
+
auto_coder-0.1.390.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
344
|
+
auto_coder-0.1.390.dist-info/METADATA,sha256=2_uomCWWJjP0IK0hnWla42dCdcAliKBgSIwz2NIygN0,2796
|
|
345
|
+
auto_coder-0.1.390.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
346
|
+
auto_coder-0.1.390.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
|
|
347
|
+
auto_coder-0.1.390.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
|
|
348
|
+
auto_coder-0.1.390.dist-info/RECORD,,
|
autocoder/auto_coder_rag.py
CHANGED
|
@@ -936,6 +936,11 @@ def main(input_args: Optional[List[str]] = None):
|
|
|
936
936
|
logger.error(
|
|
937
937
|
"The document retriever does not support hybrid index building"
|
|
938
938
|
)
|
|
939
|
+
try:
|
|
940
|
+
monitor = FileMonitor(args.doc_dir)
|
|
941
|
+
monitor.stop()
|
|
942
|
+
except Exception as e:
|
|
943
|
+
logger.warning(f"Failed to stop file monitor: {e}")
|
|
939
944
|
|
|
940
945
|
elif args.command == "tools":
|
|
941
946
|
if args.tool == "count":
|
autocoder/auto_coder_runner.py
CHANGED
|
@@ -258,6 +258,7 @@ def configure_logger():
|
|
|
258
258
|
]
|
|
259
259
|
)
|
|
260
260
|
|
|
261
|
+
|
|
261
262
|
def init_singleton_instances():
|
|
262
263
|
# 初始化文件监控系统
|
|
263
264
|
try:
|
|
@@ -275,9 +276,17 @@ def init_singleton_instances():
|
|
|
275
276
|
_ = IgnoreFileManager(project_root=project_root)
|
|
276
277
|
|
|
277
278
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
279
|
+
def start():
|
|
280
|
+
if os.environ.get('autocoder_auto_init',"true") in ["true","True","True",True]:
|
|
281
|
+
configure_logger()
|
|
282
|
+
init_singleton_instances()
|
|
283
|
+
|
|
284
|
+
def stop():
|
|
285
|
+
try:
|
|
286
|
+
FileMonitor(project_root).stop()
|
|
287
|
+
except Exception as e:
|
|
288
|
+
global_logger.error(f"Failed to stop file monitor: {e}")
|
|
289
|
+
global_logger.exception(e)
|
|
281
290
|
|
|
282
291
|
def initialize_system(args:InitializeSystemRequest):
|
|
283
292
|
from autocoder.utils.model_provider_selector import ModelProviderSelector
|
autocoder/chat_auto_coder.py
CHANGED
|
@@ -52,7 +52,9 @@ from autocoder.auto_coder_runner import (
|
|
|
52
52
|
summon,
|
|
53
53
|
get_memory,
|
|
54
54
|
active_context,
|
|
55
|
-
rules
|
|
55
|
+
rules,
|
|
56
|
+
start as start_engine,
|
|
57
|
+
stop as stop_engine
|
|
56
58
|
)
|
|
57
59
|
# Ensure the correct import is present
|
|
58
60
|
from autocoder.chat.conf_command import handle_conf_command
|
|
@@ -269,6 +271,7 @@ ARGS = None
|
|
|
269
271
|
|
|
270
272
|
def main():
|
|
271
273
|
load_tokenizer()
|
|
274
|
+
start_engine()
|
|
272
275
|
|
|
273
276
|
ARGS = parse_arguments()
|
|
274
277
|
|
|
@@ -668,13 +671,14 @@ def main():
|
|
|
668
671
|
except EOFError:
|
|
669
672
|
try:
|
|
670
673
|
# Shutdown all plugins before exiting
|
|
671
|
-
plugin_manager.shutdown_all()
|
|
674
|
+
plugin_manager.shutdown_all()
|
|
672
675
|
# save_memory()
|
|
673
676
|
try:
|
|
674
677
|
if get_mcp_server():
|
|
675
678
|
get_mcp_server().stop()
|
|
676
679
|
except Exception as e:
|
|
677
680
|
pass
|
|
681
|
+
stop_engine()
|
|
678
682
|
except Exception as e:
|
|
679
683
|
print(
|
|
680
684
|
f"\033[91mAn error occurred while saving memory:\033[0m \033[93m{type(e).__name__}\033[0m - {str(e)}"
|
autocoder/common/__init__.py
CHANGED
|
@@ -70,23 +70,22 @@ class ExecuteCommandToolResolver(BaseToolResolver):
|
|
|
70
70
|
return ToolResult(success=False, message=f"Command '{command}' contains potentially unsafe characters.")
|
|
71
71
|
|
|
72
72
|
# Approval mechanism (simplified)
|
|
73
|
-
if requires_approval:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
73
|
+
if not self.args.enable_agentic_auto_approve and requires_approval:
|
|
74
|
+
logger.info(f"Executing command: {command} in {os.path.abspath(source_dir)}")
|
|
75
|
+
try:
|
|
76
|
+
# 使用封装的run_cmd方法执行命令
|
|
77
|
+
if get_run_context().is_web():
|
|
78
|
+
answer = get_event_manager(
|
|
79
|
+
self.args.event_file).ask_user(prompt=f"Allow to execute the `{command}`?",options=["yes","no"])
|
|
80
|
+
if answer == "yes":
|
|
81
|
+
pass
|
|
82
|
+
else:
|
|
83
|
+
return ToolResult(success=False, message=f"Command '{command}' execution denied by user.")
|
|
84
|
+
except Exception as e:
|
|
85
|
+
logger.error(f"Error when ask the user to approve the command '{command}': {str(e)}")
|
|
86
|
+
return ToolResult(success=False, message=f"An unexpected error occurred while asking the user to approve the command: {str(e)}")
|
|
87
|
+
|
|
88
|
+
try:
|
|
90
89
|
exit_code, output = run_cmd_subprocess(command, verbose=True, cwd=source_dir)
|
|
91
90
|
|
|
92
91
|
logger.info(f"Command executed: {command}")
|
autocoder/memory/__init__.py
CHANGED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"""
|
|
2
|
+
当前变更模块 - 负责生成和更新 active.md 文件的当前变更部分
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
import time
|
|
7
|
+
from typing import Dict, Any, Optional, Tuple
|
|
8
|
+
import byzerllm
|
|
9
|
+
from byzerllm import MetaHolder
|
|
10
|
+
from loguru import logger as global_logger
|
|
11
|
+
from autocoder.common.token_cost_caculate import TokenCostCalculator, TokenUsageStats
|
|
12
|
+
from autocoder.common import AutoCoderArgs
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ActiveChanges:
|
|
16
|
+
"""
|
|
17
|
+
负责处理 active.md 文件的当前变更部分
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, llm: byzerllm.ByzerLLM, product_mode: str = "lite"):
|
|
21
|
+
"""
|
|
22
|
+
初始化当前变更处理器
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
llm: ByzerLLM实例,用于生成变更内容
|
|
26
|
+
product_mode: 产品模式,用于获取模型价格信息
|
|
27
|
+
"""
|
|
28
|
+
self.llm = llm
|
|
29
|
+
self.product_mode = product_mode
|
|
30
|
+
self.logger = global_logger.bind(name="ActiveChanges")
|
|
31
|
+
|
|
32
|
+
def generate_changes(self, context: Dict[str, Any], query: str, args: AutoCoderArgs) -> Tuple[str, Dict[str, Any]]:
|
|
33
|
+
"""
|
|
34
|
+
生成当前变更内容
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
context: 目录上下文字典
|
|
38
|
+
query: 用户查询/需求
|
|
39
|
+
args: AutoCoderArgs实例,包含配置信息
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Tuple[str, Dict[str, Any]]: 生成的变更内容和token使用统计
|
|
43
|
+
"""
|
|
44
|
+
try:
|
|
45
|
+
meta_holder = MetaHolder()
|
|
46
|
+
start_time = time.monotonic()
|
|
47
|
+
|
|
48
|
+
current_change = self.generate_current_change.with_llm(self.llm).with_meta(
|
|
49
|
+
meta_holder).run(context, query)
|
|
50
|
+
|
|
51
|
+
end_time = time.monotonic()
|
|
52
|
+
|
|
53
|
+
# 使用TokenCostCalculator跟踪token使用情况
|
|
54
|
+
token_calculator = TokenCostCalculator(logger_name="ActiveChanges", args=args)
|
|
55
|
+
stats: TokenUsageStats = token_calculator.track_token_usage(
|
|
56
|
+
llm=self.llm,
|
|
57
|
+
meta_holder=meta_holder,
|
|
58
|
+
operation_name="Current Change Generation",
|
|
59
|
+
start_time=start_time,
|
|
60
|
+
end_time=end_time,
|
|
61
|
+
product_mode=self.product_mode
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
self.logger.info(f"Current Change Generation - Total tokens: {stats.total_tokens}, Total cost: ${stats.total_cost:.6f}")
|
|
65
|
+
|
|
66
|
+
return current_change, {
|
|
67
|
+
"total_tokens": stats.total_tokens,
|
|
68
|
+
"input_tokens": stats.input_tokens,
|
|
69
|
+
"output_tokens": stats.output_tokens,
|
|
70
|
+
"cost": stats.total_cost
|
|
71
|
+
}
|
|
72
|
+
except Exception as e:
|
|
73
|
+
self.logger.error(f"Error generating changes: {e}")
|
|
74
|
+
empty_stats = {
|
|
75
|
+
"total_tokens": 0,
|
|
76
|
+
"input_tokens": 0,
|
|
77
|
+
"output_tokens": 0,
|
|
78
|
+
"cost": 0.0
|
|
79
|
+
}
|
|
80
|
+
return f"生成变更内容时出错: {str(e)}", empty_stats
|
|
81
|
+
|
|
82
|
+
def extract_changes(self, content: str) -> str:
|
|
83
|
+
"""
|
|
84
|
+
从现有内容中提取当前变更部分
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
content: 现有文件内容
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
str: 提取的当前变更部分
|
|
91
|
+
"""
|
|
92
|
+
try:
|
|
93
|
+
# 提取当前变更部分
|
|
94
|
+
current_change_match = re.search(r'## 当前变更\s*\n(.*?)(?=\n## |$)', content, re.DOTALL)
|
|
95
|
+
if current_change_match:
|
|
96
|
+
changes = current_change_match.group(1).strip()
|
|
97
|
+
self.logger.debug("Successfully extracted changes from existing content")
|
|
98
|
+
return changes
|
|
99
|
+
else:
|
|
100
|
+
self.logger.warning("No changes section found in existing content")
|
|
101
|
+
return ""
|
|
102
|
+
except Exception as e:
|
|
103
|
+
self.logger.error(f"Error extracting changes: {e}")
|
|
104
|
+
return ""
|
|
105
|
+
|
|
106
|
+
def update_changes(self, context: Dict[str, Any], query: str, existing_changes: str, args: AutoCoderArgs) -> Tuple[str, Dict[str, Any]]:
|
|
107
|
+
"""
|
|
108
|
+
更新现有的当前变更内容
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
context: 目录上下文字典
|
|
112
|
+
query: 用户查询/需求
|
|
113
|
+
existing_changes: 现有的变更内容
|
|
114
|
+
args: AutoCoderArgs实例,包含配置信息
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Tuple[str, Dict[str, Any]]: 更新后的变更内容和token使用统计
|
|
118
|
+
"""
|
|
119
|
+
try:
|
|
120
|
+
meta_holder = MetaHolder()
|
|
121
|
+
start_time = time.monotonic()
|
|
122
|
+
|
|
123
|
+
updated_changes = self.update_current_change.with_llm(self.llm).with_meta(
|
|
124
|
+
meta_holder).run(context, query, existing_changes)
|
|
125
|
+
|
|
126
|
+
end_time = time.monotonic()
|
|
127
|
+
|
|
128
|
+
# 使用TokenCostCalculator跟踪token使用情况
|
|
129
|
+
token_calculator = TokenCostCalculator(logger_name="ActiveChanges", args=args)
|
|
130
|
+
stats: TokenUsageStats = token_calculator.track_token_usage(
|
|
131
|
+
llm=self.llm,
|
|
132
|
+
meta_holder=meta_holder,
|
|
133
|
+
operation_name="Update Current Change",
|
|
134
|
+
start_time=start_time,
|
|
135
|
+
end_time=end_time,
|
|
136
|
+
product_mode=self.product_mode
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
self.logger.info(f"Current Change Update - Total tokens: {stats.total_tokens}, Total cost: ${stats.total_cost:.6f}")
|
|
140
|
+
|
|
141
|
+
return updated_changes, {
|
|
142
|
+
"total_tokens": stats.total_tokens,
|
|
143
|
+
"input_tokens": stats.input_tokens,
|
|
144
|
+
"output_tokens": stats.output_tokens,
|
|
145
|
+
"cost": stats.total_cost
|
|
146
|
+
}
|
|
147
|
+
except Exception as e:
|
|
148
|
+
self.logger.error(f"Error updating changes: {e}")
|
|
149
|
+
empty_stats = {
|
|
150
|
+
"total_tokens": 0,
|
|
151
|
+
"input_tokens": 0,
|
|
152
|
+
"output_tokens": 0,
|
|
153
|
+
"cost": 0.0
|
|
154
|
+
}
|
|
155
|
+
return f"更新变更内容时出错: {str(e)}", empty_stats
|
|
156
|
+
|
|
157
|
+
@byzerllm.prompt()
|
|
158
|
+
def update_current_change(self, context: Dict[str, Any], query: str, existing_current_change: str) -> str:
|
|
159
|
+
"""
|
|
160
|
+
请基于现有的"当前变更"文档和新的变更信息,生成一个更新后的"当前变更"部分。
|
|
161
|
+
|
|
162
|
+
现有的"当前变更"内容:
|
|
163
|
+
```
|
|
164
|
+
{{ existing_current_change }}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
当前需求:
|
|
168
|
+
{{ query }}
|
|
169
|
+
|
|
170
|
+
目录:{{ context.directory_path }}
|
|
171
|
+
|
|
172
|
+
最新变更的文件:
|
|
173
|
+
{% for file in context.changed_files %}
|
|
174
|
+
- {{ file.path }}
|
|
175
|
+
{% endfor %}
|
|
176
|
+
|
|
177
|
+
{% if context.file_diffs %}
|
|
178
|
+
文件变更摘要:
|
|
179
|
+
{% for diff in context.file_diffs %}
|
|
180
|
+
- {{ diff.path }}: {% if diff.type == 'modified' %}修改 (从{{ diff.before_lines }}行到{{ diff.after_lines }}行){% elif diff.type == 'added' %}新增{% elif diff.type == 'deleted' %}删除{% endif %}
|
|
181
|
+
{% endfor %}
|
|
182
|
+
{% endif %}
|
|
183
|
+
|
|
184
|
+
{% if context.changed_files and context.changed_files[0].has_diff %}
|
|
185
|
+
变更前后的代码对比:
|
|
186
|
+
{% for file in context.changed_files %}
|
|
187
|
+
{% if file.has_diff %}
|
|
188
|
+
文件: {{ file.path }}
|
|
189
|
+
变更前:
|
|
190
|
+
```
|
|
191
|
+
{{ file.before_content }}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
变更后:
|
|
195
|
+
```
|
|
196
|
+
{{ file.after_content }}
|
|
197
|
+
```
|
|
198
|
+
{% endif %}
|
|
199
|
+
{% endfor %}
|
|
200
|
+
{% endif %}
|
|
201
|
+
|
|
202
|
+
请执行以下任务:
|
|
203
|
+
1. 保留现有文档中的有用历史信息
|
|
204
|
+
2. 添加最新的变更信息,重点描述当前需求相关的变更
|
|
205
|
+
3. 明确指出新的变更与之前变更的关系(如继续完善、修复问题、新增功能等)
|
|
206
|
+
4. 确保变更描述清晰、具体,并表明每个文件的变更内容和目的
|
|
207
|
+
5. 如果有冲突的信息,优先保留最新的信息
|
|
208
|
+
6. 变更部分最多保留20条。
|
|
209
|
+
|
|
210
|
+
你的回答应该是一个完整的"当前变更"部分内容,不需要包含标题。
|
|
211
|
+
"""
|
|
212
|
+
|
|
213
|
+
@byzerllm.prompt()
|
|
214
|
+
def generate_current_change(self, context: Dict[str, Any], query: str) -> str:
|
|
215
|
+
"""
|
|
216
|
+
请分析下面的代码变更,并描述它们与当前需求的关系。
|
|
217
|
+
|
|
218
|
+
需求:
|
|
219
|
+
{{ query }}
|
|
220
|
+
|
|
221
|
+
目录:{{ context.directory_path }}
|
|
222
|
+
|
|
223
|
+
变更的文件:
|
|
224
|
+
{% for file in context.changed_files %}
|
|
225
|
+
- {{ file.path }}
|
|
226
|
+
{% endfor %}
|
|
227
|
+
|
|
228
|
+
{% if context.file_diffs %}
|
|
229
|
+
文件变更摘要:
|
|
230
|
+
{% for diff in context.file_diffs %}
|
|
231
|
+
- {{ diff.path }}: {% if diff.type == 'modified' %}修改 (从{{ diff.before_lines }}行到{{ diff.after_lines }}行){% elif diff.type == 'added' %}新增{% elif diff.type == 'deleted' %}删除{% endif %}
|
|
232
|
+
{% endfor %}
|
|
233
|
+
{% endif %}
|
|
234
|
+
|
|
235
|
+
{% if context.changed_files and context.changed_files[0].has_diff %}
|
|
236
|
+
变更前后的代码对比:
|
|
237
|
+
{% for file in context.changed_files %}
|
|
238
|
+
{% if file.has_diff %}
|
|
239
|
+
文件: {{ file.path }}
|
|
240
|
+
变更前:
|
|
241
|
+
```
|
|
242
|
+
{{ file.before_content }}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
变更后:
|
|
246
|
+
```
|
|
247
|
+
{{ file.after_content }}
|
|
248
|
+
```
|
|
249
|
+
{% endif %}
|
|
250
|
+
{% endfor %}
|
|
251
|
+
{% endif %}
|
|
252
|
+
|
|
253
|
+
分析并描述这些变更如何满足需求,以及这个目录中的文件在整体变更中起到什么作用。
|
|
254
|
+
描述应该清晰、具体,并表明每个文件的变更内容和目的。
|
|
255
|
+
"""
|