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
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""
|
|
2
|
+
活动图表模块 - 负责生成和更新 active.md 文件的 Mermaid 图表部分
|
|
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 ActiveDiagrams:
|
|
16
|
+
"""
|
|
17
|
+
负责处理 active.md 文件的 Mermaid 图表部分
|
|
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="ActiveDiagrams")
|
|
31
|
+
|
|
32
|
+
def generate_diagrams(self, context: Dict[str, Any], query: str, args: AutoCoderArgs) -> Tuple[str, Dict[str, Any]]:
|
|
33
|
+
"""
|
|
34
|
+
生成 Mermaid 图表内容
|
|
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
|
+
diagrams = self.generate_mermaid_diagrams.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="ActiveDiagrams", args=args)
|
|
55
|
+
stats: TokenUsageStats = token_calculator.track_token_usage(
|
|
56
|
+
llm=self.llm,
|
|
57
|
+
meta_holder=meta_holder,
|
|
58
|
+
operation_name="Diagram Generation",
|
|
59
|
+
start_time=start_time,
|
|
60
|
+
end_time=end_time,
|
|
61
|
+
product_mode=self.product_mode
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
self.logger.info(f"Diagram Generation - Total tokens: {stats.total_tokens}, Total cost: ${stats.total_cost:.6f}")
|
|
65
|
+
|
|
66
|
+
return diagrams, {
|
|
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 diagrams: {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_diagrams(self, content: str) -> str:
|
|
83
|
+
"""
|
|
84
|
+
从现有内容中提取图表部分
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
content: 现有文件内容
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
str: 提取的图表部分
|
|
91
|
+
"""
|
|
92
|
+
try:
|
|
93
|
+
# 提取图表部分
|
|
94
|
+
diagram_match = re.search(r'## 关系图表\s*\n(.*?)(?=\n## |$)', content, re.DOTALL)
|
|
95
|
+
if diagram_match:
|
|
96
|
+
diagrams = diagram_match.group(1).strip()
|
|
97
|
+
self.logger.debug("Successfully extracted diagrams from existing content")
|
|
98
|
+
return diagrams
|
|
99
|
+
else:
|
|
100
|
+
self.logger.warning("No diagrams section found in existing content")
|
|
101
|
+
return ""
|
|
102
|
+
except Exception as e:
|
|
103
|
+
self.logger.error(f"Error extracting diagrams: {e}")
|
|
104
|
+
return ""
|
|
105
|
+
|
|
106
|
+
def update_diagrams(self, context: Dict[str, Any], query: str, existing_diagrams: str, args: AutoCoderArgs) -> Tuple[str, Dict[str, Any]]:
|
|
107
|
+
"""
|
|
108
|
+
更新现有的图表内容
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
context: 目录上下文字典
|
|
112
|
+
query: 用户查询/需求
|
|
113
|
+
existing_diagrams: 现有的图表内容
|
|
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_diagrams = self.update_mermaid_diagrams.with_llm(self.llm).with_meta(
|
|
124
|
+
meta_holder).run(context, query, existing_diagrams)
|
|
125
|
+
|
|
126
|
+
end_time = time.monotonic()
|
|
127
|
+
|
|
128
|
+
# 使用TokenCostCalculator跟踪token使用情况
|
|
129
|
+
token_calculator = TokenCostCalculator(logger_name="ActiveDiagrams", args=args)
|
|
130
|
+
stats: TokenUsageStats = token_calculator.track_token_usage(
|
|
131
|
+
llm=self.llm,
|
|
132
|
+
meta_holder=meta_holder,
|
|
133
|
+
operation_name="Update Diagrams",
|
|
134
|
+
start_time=start_time,
|
|
135
|
+
end_time=end_time,
|
|
136
|
+
product_mode=self.product_mode
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
self.logger.info(f"Diagrams Update - Total tokens: {stats.total_tokens}, Total cost: ${stats.total_cost:.6f}")
|
|
140
|
+
|
|
141
|
+
return updated_diagrams, {
|
|
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 diagrams: {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_mermaid_diagrams(self, context: Dict[str, Any], query: str, existing_diagrams: str) -> str:
|
|
159
|
+
"""
|
|
160
|
+
请基于现有的"关系图表"部分和新的变更信息,生成一个更新后的"关系图表"部分。
|
|
161
|
+
|
|
162
|
+
现有的"关系图表"内容:
|
|
163
|
+
```
|
|
164
|
+
{{ existing_diagrams }}
|
|
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.current_files %}
|
|
178
|
+
当前目录中的其他相关文件:
|
|
179
|
+
{% for file in context.current_files %}
|
|
180
|
+
- {{ file.path }}
|
|
181
|
+
{% endfor %}
|
|
182
|
+
{% endif %}
|
|
183
|
+
|
|
184
|
+
{% if context.file_diffs %}
|
|
185
|
+
文件变更摘要:
|
|
186
|
+
{% for diff in context.file_diffs %}
|
|
187
|
+
- {{ diff.path }}: {% if diff.type == 'modified' %}修改 (从{{ diff.before_lines }}行到{{ diff.after_lines }}行){% elif diff.type == 'added' %}新增{% elif diff.type == 'deleted' %}删除{% endif %}
|
|
188
|
+
{% endfor %}
|
|
189
|
+
{% endif %}
|
|
190
|
+
|
|
191
|
+
{% if context.changed_files and context.changed_files[0].has_diff %}
|
|
192
|
+
变更前后的代码对比:
|
|
193
|
+
{% for file in context.changed_files %}
|
|
194
|
+
{% if file.has_diff %}
|
|
195
|
+
文件: {{ file.path }}
|
|
196
|
+
变更前:
|
|
197
|
+
```
|
|
198
|
+
{{ file.before_content }}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
变更后:
|
|
202
|
+
```
|
|
203
|
+
{{ file.after_content }}
|
|
204
|
+
```
|
|
205
|
+
{% endif %}
|
|
206
|
+
{% endfor %}
|
|
207
|
+
{% endif %}
|
|
208
|
+
|
|
209
|
+
请执行以下任务:
|
|
210
|
+
1. 分析现有图表的准确性,保留正确的关系信息
|
|
211
|
+
2. 根据最新的变更更新文件之间的关系图
|
|
212
|
+
3. 更新函数/类之间的调用关系图
|
|
213
|
+
4. 如果有新文件或新函数,将它们添加到相应的图表中
|
|
214
|
+
5. 确保 Mermaid 语法正确,图表清晰易读
|
|
215
|
+
6. 如有冲突信息,优先保留最新信息
|
|
216
|
+
|
|
217
|
+
请生成以下两个图表:
|
|
218
|
+
|
|
219
|
+
### 文件关系图
|
|
220
|
+
使用 Mermaid graph 语法展示文件之间的依赖关系、导入关系等。
|
|
221
|
+
|
|
222
|
+
### 函数/类关系图
|
|
223
|
+
使用 Mermaid graph 或 classDiagram 语法展示主要函数和类之间的调用关系。
|
|
224
|
+
|
|
225
|
+
你的回答应该是一个完整的"关系图表"部分内容,不需要包含标题。
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
@byzerllm.prompt()
|
|
229
|
+
def generate_mermaid_diagrams(self, context: Dict[str, Any], query: str) -> str:
|
|
230
|
+
"""
|
|
231
|
+
请根据下面的代码变更信息,生成 Mermaid 图表来展示文件之间的关系和函数之间的关系。
|
|
232
|
+
|
|
233
|
+
需求:
|
|
234
|
+
{{ query }}
|
|
235
|
+
|
|
236
|
+
目录:{{ context.directory_path }}
|
|
237
|
+
|
|
238
|
+
文件列表:
|
|
239
|
+
{% for file in context.changed_files %}
|
|
240
|
+
- {{ file.path }}
|
|
241
|
+
{% endfor %}
|
|
242
|
+
|
|
243
|
+
{% if context.current_files %}
|
|
244
|
+
当前目录中的其他相关文件:
|
|
245
|
+
{% for file in context.current_files %}
|
|
246
|
+
- {{ file.path }}
|
|
247
|
+
{% endfor %}
|
|
248
|
+
{% endif %}
|
|
249
|
+
|
|
250
|
+
{% if context.file_diffs %}
|
|
251
|
+
文件变更摘要:
|
|
252
|
+
{% for diff in context.file_diffs %}
|
|
253
|
+
- {{ diff.path }}: {% if diff.type == 'modified' %}修改 (从{{ diff.before_lines }}行到{{ diff.after_lines }}行){% elif diff.type == 'added' %}新增{% elif diff.type == 'deleted' %}删除{% endif %}
|
|
254
|
+
{% endfor %}
|
|
255
|
+
{% endif %}
|
|
256
|
+
|
|
257
|
+
{% if context.changed_files and context.changed_files[0].has_diff %}
|
|
258
|
+
变更前后的代码对比:
|
|
259
|
+
{% for file in context.changed_files %}
|
|
260
|
+
{% if file.has_diff %}
|
|
261
|
+
文件: {{ file.path }}
|
|
262
|
+
变更前:
|
|
263
|
+
```
|
|
264
|
+
{{ file.before_content }}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
变更后:
|
|
268
|
+
```
|
|
269
|
+
{{ file.after_content }}
|
|
270
|
+
```
|
|
271
|
+
{% endif %}
|
|
272
|
+
{% endfor %}
|
|
273
|
+
{% endif %}
|
|
274
|
+
|
|
275
|
+
请分析代码变更,生成以下两个 Mermaid 图表:
|
|
276
|
+
|
|
277
|
+
### 文件关系图
|
|
278
|
+
分析文件之间的依赖关系、导入关系、继承关系等,使用 Mermaid graph 语法展示。
|
|
279
|
+
- 显示文件之间的导入依赖
|
|
280
|
+
- 标注关系类型(import、inherit、compose等)
|
|
281
|
+
- 突出显示本次变更涉及的文件
|
|
282
|
+
|
|
283
|
+
### 函数/类关系图
|
|
284
|
+
分析主要函数和类之间的调用关系、继承关系等,使用 Mermaid graph 或 classDiagram 语法展示。
|
|
285
|
+
- 显示类的继承关系
|
|
286
|
+
- 显示函数/方法的调用关系
|
|
287
|
+
- 突出显示本次变更涉及的函数/类
|
|
288
|
+
- 包含重要的属性和方法
|
|
289
|
+
|
|
290
|
+
要求:
|
|
291
|
+
1. 使用正确的 Mermaid 语法
|
|
292
|
+
2. 图表要清晰易读,避免过于复杂
|
|
293
|
+
3. 添加适当的注释说明关系类型
|
|
294
|
+
4. 确保图表能够帮助理解代码结构和变更影响
|
|
295
|
+
|
|
296
|
+
格式示例:
|
|
297
|
+
```mermaid
|
|
298
|
+
graph TD
|
|
299
|
+
A[文件A] -->|包含| B[文件B]
|
|
300
|
+
B -->|包含| C[文件C]
|
|
301
|
+
```
|
|
302
|
+
"""
|
|
@@ -0,0 +1,287 @@
|
|
|
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 ActiveDocuments:
|
|
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="ActiveDocuments")
|
|
31
|
+
|
|
32
|
+
def generate_documents(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
|
+
document = self.generate_document.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="ActiveDocuments", args=args)
|
|
55
|
+
stats: TokenUsageStats = token_calculator.track_token_usage(
|
|
56
|
+
llm=self.llm,
|
|
57
|
+
meta_holder=meta_holder,
|
|
58
|
+
operation_name="Document Generation",
|
|
59
|
+
start_time=start_time,
|
|
60
|
+
end_time=end_time,
|
|
61
|
+
product_mode=self.product_mode
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
self.logger.info(f"Document Generation - Total tokens: {stats.total_tokens}, Total cost: ${stats.total_cost:.6f}")
|
|
65
|
+
|
|
66
|
+
return document, {
|
|
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 documents: {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_documents(self, content: str) -> str:
|
|
83
|
+
"""
|
|
84
|
+
从现有内容中提取文档部分
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
content: 现有文件内容
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
str: 提取的文档部分
|
|
91
|
+
"""
|
|
92
|
+
try:
|
|
93
|
+
# 提取文档部分
|
|
94
|
+
document_match = re.search(r'## 文档\s*\n(.*?)(?=\n## |$)', content, re.DOTALL)
|
|
95
|
+
if document_match:
|
|
96
|
+
document = document_match.group(1).strip()
|
|
97
|
+
self.logger.debug("Successfully extracted documents from existing content")
|
|
98
|
+
return document
|
|
99
|
+
else:
|
|
100
|
+
self.logger.warning("No documents section found in existing content")
|
|
101
|
+
return ""
|
|
102
|
+
except Exception as e:
|
|
103
|
+
self.logger.error(f"Error extracting documents: {e}")
|
|
104
|
+
return ""
|
|
105
|
+
|
|
106
|
+
def update_documents(self, context: Dict[str, Any], query: str, existing_document: str, args: AutoCoderArgs) -> Tuple[str, Dict[str, Any]]:
|
|
107
|
+
"""
|
|
108
|
+
更新现有的文档内容
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
context: 目录上下文字典
|
|
112
|
+
query: 用户查询/需求
|
|
113
|
+
existing_document: 现有的文档内容
|
|
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_document = self.update_document.with_llm(self.llm).with_meta(
|
|
124
|
+
meta_holder).run(context, query, existing_document)
|
|
125
|
+
|
|
126
|
+
end_time = time.monotonic()
|
|
127
|
+
|
|
128
|
+
# 使用TokenCostCalculator跟踪token使用情况
|
|
129
|
+
token_calculator = TokenCostCalculator(logger_name="ActiveDocuments", args=args)
|
|
130
|
+
stats: TokenUsageStats = token_calculator.track_token_usage(
|
|
131
|
+
llm=self.llm,
|
|
132
|
+
meta_holder=meta_holder,
|
|
133
|
+
operation_name="Update Document",
|
|
134
|
+
start_time=start_time,
|
|
135
|
+
end_time=end_time,
|
|
136
|
+
product_mode=self.product_mode
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
self.logger.info(f"Document Update - Total tokens: {stats.total_tokens}, Total cost: ${stats.total_cost:.6f}")
|
|
140
|
+
|
|
141
|
+
return updated_document, {
|
|
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 documents: {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_document(self, context: Dict[str, Any], query: str, existing_document: str) -> str:
|
|
159
|
+
"""
|
|
160
|
+
请基于现有的"文档"部分和新的变更信息,生成一个更新后的"文档"部分。
|
|
161
|
+
|
|
162
|
+
现有的"文档"内容:
|
|
163
|
+
```
|
|
164
|
+
{{ existing_document }}
|
|
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.current_files %}
|
|
178
|
+
当前目录中的其他相关文件:
|
|
179
|
+
{% for file in context.current_files %}
|
|
180
|
+
- {{ file.path }}
|
|
181
|
+
{% endfor %}
|
|
182
|
+
{% endif %}
|
|
183
|
+
|
|
184
|
+
{% if context.file_diffs %}
|
|
185
|
+
文件变更摘要:
|
|
186
|
+
{% for diff in context.file_diffs %}
|
|
187
|
+
- {{ diff.path }}: {% if diff.type == 'modified' %}修改 (从{{ diff.before_lines }}行到{{ diff.after_lines }}行){% elif diff.type == 'added' %}新增{% elif diff.type == 'deleted' %}删除{% endif %}
|
|
188
|
+
{% endfor %}
|
|
189
|
+
{% endif %}
|
|
190
|
+
|
|
191
|
+
{% if context.changed_files and context.changed_files[0].has_diff %}
|
|
192
|
+
变更前后的代码对比:
|
|
193
|
+
{% for file in context.changed_files %}
|
|
194
|
+
{% if file.has_diff %}
|
|
195
|
+
文件: {{ file.path }}
|
|
196
|
+
变更前:
|
|
197
|
+
```
|
|
198
|
+
{{ file.before_content }}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
变更后:
|
|
202
|
+
```
|
|
203
|
+
{{ file.after_content }}
|
|
204
|
+
```
|
|
205
|
+
{% endif %}
|
|
206
|
+
{% endfor %}
|
|
207
|
+
{% endif %}
|
|
208
|
+
|
|
209
|
+
请执行以下任务:
|
|
210
|
+
1. 保留现有文档中的准确信息
|
|
211
|
+
2. 更新每个文件的文档,反映最新的变更
|
|
212
|
+
3. 如果有新文件,为其创建完整的文档
|
|
213
|
+
4. 确保文档格式一致性,每个文件的文档包含:功能、关键组件、变更影响、与其他文件的关系
|
|
214
|
+
5. 如有冲突信息,优先保留最新信息,但保留历史上下文
|
|
215
|
+
|
|
216
|
+
格式应为:
|
|
217
|
+
|
|
218
|
+
### [文件名]
|
|
219
|
+
- **功能**:
|
|
220
|
+
- **关键组件**:
|
|
221
|
+
- **变更影响**:
|
|
222
|
+
- **关系**:
|
|
223
|
+
|
|
224
|
+
你的回答应该是一个完整的"文档"部分内容,不需要包含标题。
|
|
225
|
+
"""
|
|
226
|
+
|
|
227
|
+
@byzerllm.prompt()
|
|
228
|
+
def generate_document(self, context: Dict[str, Any], query: str) -> str:
|
|
229
|
+
"""
|
|
230
|
+
请为下面列出的每个文件生成详细的文档说明。
|
|
231
|
+
|
|
232
|
+
需求:
|
|
233
|
+
{{ query }}
|
|
234
|
+
|
|
235
|
+
目录:{{ context.directory_path }}
|
|
236
|
+
|
|
237
|
+
文件列表:
|
|
238
|
+
{% for file in context.changed_files %}
|
|
239
|
+
- {{ file.path }}
|
|
240
|
+
{% endfor %}
|
|
241
|
+
|
|
242
|
+
{% if context.current_files %}
|
|
243
|
+
当前目录中的其他相关文件:
|
|
244
|
+
{% for file in context.current_files %}
|
|
245
|
+
- {{ file.path }}
|
|
246
|
+
{% endfor %}
|
|
247
|
+
{% endif %}
|
|
248
|
+
|
|
249
|
+
{% if context.file_diffs %}
|
|
250
|
+
文件变更摘要:
|
|
251
|
+
{% for diff in context.file_diffs %}
|
|
252
|
+
- {{ diff.path }}: {% if diff.type == 'modified' %}修改 (从{{ diff.before_lines }}行到{{ diff.after_lines }}行){% elif diff.type == 'added' %}新增{% elif diff.type == 'deleted' %}删除{% endif %}
|
|
253
|
+
{% endfor %}
|
|
254
|
+
{% endif %}
|
|
255
|
+
|
|
256
|
+
{% if context.changed_files and context.changed_files[0].has_diff %}
|
|
257
|
+
变更前后的代码对比:
|
|
258
|
+
{% for file in context.changed_files %}
|
|
259
|
+
{% if file.has_diff %}
|
|
260
|
+
文件: {{ file.path }}
|
|
261
|
+
变更前:
|
|
262
|
+
```
|
|
263
|
+
{{ file.before_content }}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
变更后:
|
|
267
|
+
```
|
|
268
|
+
{{ file.after_content }}
|
|
269
|
+
```
|
|
270
|
+
{% endif %}
|
|
271
|
+
{% endfor %}
|
|
272
|
+
{% endif %}
|
|
273
|
+
|
|
274
|
+
对于每个文件,请提供:
|
|
275
|
+
1. 文件的主要功能
|
|
276
|
+
2. 文件中的关键组件(类、函数等)
|
|
277
|
+
3. 此次变更对文件的影响(如果适用)
|
|
278
|
+
4. 文件与其他文件的关系
|
|
279
|
+
|
|
280
|
+
格式应为:
|
|
281
|
+
|
|
282
|
+
### [文件名]
|
|
283
|
+
- **功能**:
|
|
284
|
+
- **关键组件**:
|
|
285
|
+
- **变更影响**:
|
|
286
|
+
- **关系**:
|
|
287
|
+
"""
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
活动上下文标题模块 - 负责生成和更新 active.md 文件的标题部分
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
from typing import Dict, Any, Optional
|
|
8
|
+
from loguru import logger as global_logger
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ActiveHeader:
|
|
12
|
+
"""
|
|
13
|
+
负责处理 active.md 文件的标题部分
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
"""初始化活动标题处理器"""
|
|
18
|
+
self.logger = global_logger.bind(name="ActiveHeader")
|
|
19
|
+
|
|
20
|
+
def generate_header(self, context: Dict[str, Any]) -> str:
|
|
21
|
+
"""
|
|
22
|
+
生成活动上下文标题
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
context: 目录上下文字典
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
str: 生成的标题内容
|
|
29
|
+
"""
|
|
30
|
+
try:
|
|
31
|
+
# 安全获取目录名称
|
|
32
|
+
dir_name = os.path.basename(context.get('directory_path', '未知目录'))
|
|
33
|
+
header = f"# 活动上下文 - {dir_name}\n\n"
|
|
34
|
+
|
|
35
|
+
self.logger.debug(f"Generated header for directory: {dir_name}")
|
|
36
|
+
return header
|
|
37
|
+
except Exception as e:
|
|
38
|
+
self.logger.error(f"Error generating header: {e}")
|
|
39
|
+
return "# 活动上下文 - 未知目录\n\n"
|
|
40
|
+
|
|
41
|
+
def extract_header(self, content: str) -> str:
|
|
42
|
+
"""
|
|
43
|
+
从现有内容中提取标题部分
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
content: 现有文件内容
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
str: 提取的标题部分
|
|
50
|
+
"""
|
|
51
|
+
try:
|
|
52
|
+
# 提取标题部分(到第一个二级标题之前)
|
|
53
|
+
header_match = re.search(r'^(.*?)(?=\n## )', content, re.DOTALL)
|
|
54
|
+
if header_match:
|
|
55
|
+
header = header_match.group(1).strip() + "\n\n"
|
|
56
|
+
self.logger.debug("Successfully extracted header from existing content")
|
|
57
|
+
return header
|
|
58
|
+
else:
|
|
59
|
+
self.logger.warning("No header found in existing content, using default")
|
|
60
|
+
return "# 活动上下文\n\n"
|
|
61
|
+
except Exception as e:
|
|
62
|
+
self.logger.error(f"Error extracting header: {e}")
|
|
63
|
+
return "# 活动上下文\n\n"
|
|
64
|
+
|
|
65
|
+
def update_header(self, context: Dict[str, Any], existing_header: str) -> str:
|
|
66
|
+
"""
|
|
67
|
+
更新现有的标题部分
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
context: 目录上下文字典
|
|
71
|
+
existing_header: 现有的标题内容
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
str: 更新后的标题内容
|
|
75
|
+
"""
|
|
76
|
+
try:
|
|
77
|
+
# 如果现有标题包含正确的目录名,则保留;否则更新
|
|
78
|
+
dir_name = os.path.basename(context.get('directory_path', '未知目录'))
|
|
79
|
+
|
|
80
|
+
if dir_name in existing_header and existing_header.strip():
|
|
81
|
+
self.logger.debug(f"Keeping existing header for directory: {dir_name}")
|
|
82
|
+
return existing_header
|
|
83
|
+
else:
|
|
84
|
+
self.logger.debug(f"Updating header for directory: {dir_name}")
|
|
85
|
+
return self.generate_header(context)
|
|
86
|
+
except Exception as e:
|
|
87
|
+
self.logger.error(f"Error updating header: {e}")
|
|
88
|
+
return self.generate_header(context)
|