auto-coder 0.1.388__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: auto-coder
3
- Version: 0.1.388
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.186
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=tRAKfo3jIhcaQKN_3g7DZRKtDJSZXJxMRdT6Zz8W9nw,41173
4
- autocoder/auto_coder_runner.py,sha256=NhT1fVdV4NnV2SwpXl7G-tTKgduA0D-0lK_p2R6DWew,115569
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=vNQwbYkdqeMl07Vx8z6x-kSPkHKn9AT3sSkYMTJiWtc,26655
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=hNsmB1tFGyMvodXf4gkbGjHmHME4WMQKrmpne8xb3T0,25
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=qZWLTeEjimIGDUvbAq_QV1o5jgMiD1k4TQcoU0-wOo8,14887
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=8dCjSvpo09QG4Jj-kh5iOTQtikp87W0Z6q_6XyezQDo,5439
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=5FeGvsesRViYL4BkFiHw9SdlyHeWlqALpTyqOpfnBRw,179
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/active_package.py,sha256=NHLLnncFSfFcOFLWILwJLuEVd4nOoL0mqzFev6QHgzU,25480
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
@@ -264,14 +268,14 @@ autocoder/privacy/model_filter.py,sha256=RyGh_uWWE6hHqvaYZGjFylDJldDLxBz5LDZP7CG
264
268
  autocoder/pyproject/__init__.py,sha256=qn0_-6O_LP-ZH91nneYrn3yaIMYCYYRD1Z3MSNhXUXI,13754
265
269
  autocoder/rag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
266
270
  autocoder/rag/agentic_rag.py,sha256=sXs1qo696zp6ZFaueYDa6AKBzy7O8x9D3wgTkC0zjr4,7851
267
- autocoder/rag/api_server.py,sha256=TNN5CmR1nlMgeuZVYZ1U3a48XBp647Io9P-VvCkdI9o,13936
271
+ autocoder/rag/api_server.py,sha256=fFJs4-BxCkKRJwmqupkcEOZwwe5ALBew0QTw6JszaXY,14236
268
272
  autocoder/rag/conversation_to_queries.py,sha256=QUeRacDZVVd5XiDvKZ1G71h2QpfmfZldc27Is6sTMdU,6508
269
273
  autocoder/rag/doc_filter.py,sha256=UduVO2mlrngwJICrefjDJTYfdmQ4GcRXrfWDQ7xXksk,14206
270
274
  autocoder/rag/document_retriever.py,sha256=rFwbAuHTvEFJq16HQNlmRLyJp2ddn2RNFslw_ncU7NI,8847
271
- autocoder/rag/lang.py,sha256=HvcMeu6jReEJOGxyLMn4rwBoD-myFwmykS3VLceBJLs,3364
275
+ autocoder/rag/lang.py,sha256=TRtbyicotAQdOU5SDDTNvddAo9Lz2T0WCSvc1JNlrlQ,3459
272
276
  autocoder/rag/llm_wrapper.py,sha256=LsNv8maCnvazyXjjtkO9aN3OT7Br20V1ilHV8Lt45Os,4245
273
- autocoder/rag/long_context_rag.py,sha256=z5A_RTIgNq52ridpBAiaUQfkvUtrFtnnmBVuTBNiH_I,52970
274
- autocoder/rag/qa_conversation_strategy.py,sha256=4CiMK88apKbJ2YM4HHq1KGpr5jUkTh0_m_aCyt-JYgc,10568
277
+ autocoder/rag/long_context_rag.py,sha256=t9SEhkc0Rc1nWcezj_fANvsUVH5lFZ6ZpWtyBqJl4jk,53236
278
+ autocoder/rag/qa_conversation_strategy.py,sha256=MdOBP7aZUtOSou5vQhDcUxySBCVZXytZwNqmrGW6fXg,10700
275
279
  autocoder/rag/rag_config.py,sha256=8LwFcTd8OJWWwi1_WY4IzjqgtT6RyE2j4PjxS5cCTDE,802
276
280
  autocoder/rag/rag_entry.py,sha256=QOdUX_nd1Qak2NyOW0CYcLRDB26AZ6MeByHJaMMGgqs,2316
277
281
  autocoder/rag/relevant_utils.py,sha256=25wRiX-CrBsratASLGHsZE3ux7VjwaQoDNtl74UlV5U,1749
@@ -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.388.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
340
- auto_coder-0.1.388.dist-info/METADATA,sha256=fjJIU0SQjvcMLq6RwM8_uFL9u4AvvnwI3GeEUwEEUzg,2796
341
- auto_coder-0.1.388.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
342
- auto_coder-0.1.388.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
343
- auto_coder-0.1.388.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
344
- auto_coder-0.1.388.dist-info/RECORD,,
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,,
@@ -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":
@@ -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
- if os.environ.get('autocoder_auto_init',"true") in ["true","True","True",True]:
279
- configure_logger()
280
- init_singleton_instances()
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
@@ -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)}"
@@ -275,6 +275,7 @@ class AutoCoderArgs(pydantic.BaseModel):
275
275
 
276
276
  enable_agentic_filter: Optional[bool] = False
277
277
  enable_agentic_edit: Optional[bool] = True
278
+ enable_agentic_auto_approve: Optional[bool] = False
278
279
 
279
280
 
280
281
  index_filter_level: Optional[int] = 0
@@ -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
- # In a real scenario, this would involve user interaction
75
- logger.info(f"Command requires approval: {command}")
76
- # For now, let's assume approval is granted in non-interactive mode or handled elsewhere
77
- pass
78
-
79
- logger.info(f"Executing command: {command} in {os.path.abspath(source_dir)}")
80
- try:
81
- # 使用封装的run_cmd方法执行命令
82
- if get_run_context().is_web():
83
- answer = get_event_manager(
84
- self.args.event_file).ask_user(prompt=f"Allow to execute the `{command}`?",options=["yes","no"])
85
- if answer == "yes":
86
- pass
87
- else:
88
- return ToolResult(success=False, message=f"Command '{command}' execution denied by user.")
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}")
@@ -1,7 +0,0 @@
1
- """
2
- 记忆子系统 - 用于跟踪和记录代码变更上下文
3
- """
4
-
5
- from autocoder.memory.active_context_manager import ActiveContextManager
6
-
7
- __all__ = ["ActiveContextManager"]
@@ -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
+ """