auto-coder 0.1.301__py3-none-any.whl → 0.1.303__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.301.dist-info → auto_coder-0.1.303.dist-info}/METADATA +2 -1
- {auto_coder-0.1.301.dist-info → auto_coder-0.1.303.dist-info}/RECORD +33 -25
- autocoder/auto_coder.py +6 -7
- autocoder/auto_coder_runner.py +9 -9
- autocoder/chat_auto_coder.py +6 -1
- autocoder/commands/auto_command.py +313 -205
- autocoder/commands/tools.py +123 -85
- autocoder/common/__init__.py +2 -0
- autocoder/common/action_yml_file_manager.py +28 -6
- autocoder/common/auto_coder_lang.py +2 -2
- autocoder/common/auto_configure.py +9 -4
- autocoder/common/code_auto_merge.py +1 -1
- autocoder/common/code_auto_merge_diff.py +1 -1
- autocoder/common/code_auto_merge_editblock.py +1 -1
- autocoder/common/code_auto_merge_strict_diff.py +1 -1
- autocoder/common/stream_out_type.py +7 -0
- autocoder/dispacher/actions/action.py +221 -101
- autocoder/dispacher/actions/plugins/action_regex_project.py +18 -0
- autocoder/events/__init__.py +57 -0
- autocoder/events/event_content.py +423 -0
- autocoder/events/event_manager.py +327 -0
- autocoder/events/event_manager_singleton.py +245 -0
- autocoder/events/event_store.py +376 -0
- autocoder/events/event_types.py +103 -0
- autocoder/index/entry.py +88 -60
- autocoder/index/filter/quick_filter.py +71 -3
- autocoder/run_context.py +62 -0
- autocoder/utils/auto_coder_utils/chat_stream_out.py +32 -1
- autocoder/version.py +1 -1
- {auto_coder-0.1.301.dist-info → auto_coder-0.1.303.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.301.dist-info → auto_coder-0.1.303.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.301.dist-info → auto_coder-0.1.303.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.301.dist-info → auto_coder-0.1.303.dist-info}/top_level.txt +0 -0
autocoder/index/entry.py
CHANGED
|
@@ -10,6 +10,7 @@ from rich.table import Table
|
|
|
10
10
|
from rich.panel import Panel
|
|
11
11
|
|
|
12
12
|
from autocoder.common.printer import Printer
|
|
13
|
+
from autocoder.events.event_types import EventMetadata
|
|
13
14
|
from autocoder.utils.queue_communicate import (
|
|
14
15
|
queue_communicate,
|
|
15
16
|
CommunicateEvent,
|
|
@@ -27,10 +28,14 @@ from autocoder.common import SourceCodeList
|
|
|
27
28
|
from autocoder.common.context_pruner import PruneContext
|
|
28
29
|
from autocoder.common.action_yml_file_manager import ActionYmlFileManager
|
|
29
30
|
|
|
31
|
+
from autocoder.events.event_manager_singleton import get_event_manager
|
|
32
|
+
from autocoder.events import event_content as EventContentCreator
|
|
33
|
+
|
|
34
|
+
|
|
30
35
|
def build_index_and_filter_files(
|
|
31
36
|
llm, args: AutoCoderArgs, sources: List[SourceCode]
|
|
32
37
|
) -> SourceCodeList:
|
|
33
|
-
|
|
38
|
+
|
|
34
39
|
action_yml_file_manager = ActionYmlFileManager(args.source_dir)
|
|
35
40
|
# Initialize timing and statistics
|
|
36
41
|
total_start_time = time.monotonic()
|
|
@@ -61,11 +66,11 @@ def build_index_and_filter_files(
|
|
|
61
66
|
return file_path.strip()[2:]
|
|
62
67
|
return file_path
|
|
63
68
|
|
|
64
|
-
# 文件路径 -> TargetFile
|
|
69
|
+
# 文件路径 -> TargetFile
|
|
65
70
|
final_files: Dict[str, TargetFile] = {}
|
|
66
71
|
|
|
67
72
|
# 文件路径 -> 文件在文件列表中的位置(越前面表示越相关)
|
|
68
|
-
file_positions:Dict[str,int] = {}
|
|
73
|
+
file_positions: Dict[str, int] = {}
|
|
69
74
|
|
|
70
75
|
# Phase 1: Process REST/RAG/Search sources
|
|
71
76
|
printer = Printer()
|
|
@@ -78,7 +83,7 @@ def build_index_and_filter_files(
|
|
|
78
83
|
)
|
|
79
84
|
phase_end = time.monotonic()
|
|
80
85
|
stats["timings"]["process_tagged_sources"] = phase_end - phase_start
|
|
81
|
-
|
|
86
|
+
|
|
82
87
|
if not args.skip_build_index and llm:
|
|
83
88
|
# Phase 2: Build index
|
|
84
89
|
if args.request_id and not args.skip_events:
|
|
@@ -109,31 +114,34 @@ def build_index_and_filter_files(
|
|
|
109
114
|
})
|
|
110
115
|
)
|
|
111
116
|
)
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
|
|
114
118
|
if not args.skip_filter_index and args.index_filter_model:
|
|
115
|
-
model_name = getattr(
|
|
119
|
+
model_name = getattr(
|
|
120
|
+
index_manager.index_filter_llm, 'default_model_name', None)
|
|
116
121
|
if not model_name:
|
|
117
|
-
model_name = "unknown(without default model name)"
|
|
118
|
-
printer.print_in_terminal(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
+
model_name = "unknown(without default model name)"
|
|
123
|
+
printer.print_in_terminal(
|
|
124
|
+
"quick_filter_start", style="blue", model_name=model_name)
|
|
125
|
+
quick_filter = QuickFilter(index_manager, stats, sources)
|
|
126
|
+
quick_filter_result = quick_filter.filter(
|
|
127
|
+
index_manager.read_index(), args.query)
|
|
128
|
+
|
|
122
129
|
final_files.update(quick_filter_result.files)
|
|
123
|
-
|
|
130
|
+
|
|
124
131
|
if quick_filter_result.file_positions:
|
|
125
132
|
file_positions.update(quick_filter_result.file_positions)
|
|
126
|
-
|
|
133
|
+
|
|
127
134
|
if not args.skip_filter_index and not args.index_filter_model:
|
|
128
135
|
model_name = getattr(index_manager.llm, 'default_model_name', None)
|
|
129
136
|
if not model_name:
|
|
130
|
-
model_name = "unknown(without default model name)"
|
|
131
|
-
printer.print_in_terminal(
|
|
132
|
-
|
|
133
|
-
|
|
137
|
+
model_name = "unknown(without default model name)"
|
|
138
|
+
printer.print_in_terminal(
|
|
139
|
+
"normal_filter_start", style="blue", model_name=model_name)
|
|
140
|
+
normal_filter = NormalFilter(index_manager, stats, sources)
|
|
141
|
+
normal_filter_result = normal_filter.filter(
|
|
142
|
+
index_manager.read_index(), args.query)
|
|
134
143
|
# Merge normal filter results into final_files
|
|
135
144
|
final_files.update(normal_filter_result.files)
|
|
136
|
-
|
|
137
145
|
|
|
138
146
|
def display_table_and_get_selections(data):
|
|
139
147
|
from prompt_toolkit.shortcuts import checkboxlist_dialog
|
|
@@ -173,7 +181,7 @@ def build_index_and_filter_files(
|
|
|
173
181
|
|
|
174
182
|
def print_selected(data):
|
|
175
183
|
console = Console()
|
|
176
|
-
|
|
184
|
+
|
|
177
185
|
# 获取终端宽度
|
|
178
186
|
console_width = console.width
|
|
179
187
|
|
|
@@ -185,18 +193,19 @@ def build_index_and_filter_files(
|
|
|
185
193
|
width=min(console_width - 10, 120),
|
|
186
194
|
expand=True
|
|
187
195
|
)
|
|
188
|
-
|
|
196
|
+
|
|
189
197
|
# 优化列配置
|
|
190
|
-
table.add_column("File Path",
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
table.add_column("File Path",
|
|
199
|
+
style="cyan",
|
|
200
|
+
# 分配 60% 宽度给文件路径
|
|
201
|
+
width=int((console_width - 10) * 0.6),
|
|
202
|
+
overflow="fold", # 自动折叠过长的路径
|
|
203
|
+
no_wrap=False) # 允许换行
|
|
204
|
+
|
|
205
|
+
table.add_column("Reason",
|
|
206
|
+
style="green",
|
|
207
|
+
width=int((console_width - 10) * 0.4), # 分配 40% 宽度给原因
|
|
208
|
+
no_wrap=False)
|
|
200
209
|
|
|
201
210
|
# 添加处理过的文件路径
|
|
202
211
|
for file, reason in data:
|
|
@@ -215,7 +224,7 @@ def build_index_and_filter_files(
|
|
|
215
224
|
|
|
216
225
|
# Phase 6: File selection and limitation
|
|
217
226
|
printer.print_in_terminal("phase6_file_selection")
|
|
218
|
-
phase_start = time.monotonic()
|
|
227
|
+
phase_start = time.monotonic()
|
|
219
228
|
|
|
220
229
|
if args.index_filter_file_num > 0:
|
|
221
230
|
logger.info(
|
|
@@ -246,7 +255,7 @@ def build_index_and_filter_files(
|
|
|
246
255
|
|
|
247
256
|
# Phase 7: Display results and prepare output
|
|
248
257
|
printer.print_in_terminal("phase7_preparing_output")
|
|
249
|
-
phase_start = time.monotonic()
|
|
258
|
+
phase_start = time.monotonic()
|
|
250
259
|
try:
|
|
251
260
|
print_selected(
|
|
252
261
|
[
|
|
@@ -263,11 +272,11 @@ def build_index_and_filter_files(
|
|
|
263
272
|
for file in final_filenames:
|
|
264
273
|
print(f"{file} - {final_files[file].reason}")
|
|
265
274
|
|
|
266
|
-
# source_code = ""
|
|
275
|
+
# source_code = ""
|
|
267
276
|
source_code_list = SourceCodeList(sources=[])
|
|
268
277
|
depulicated_sources = set()
|
|
269
|
-
|
|
270
|
-
|
|
278
|
+
|
|
279
|
+
# 先去重
|
|
271
280
|
temp_sources = []
|
|
272
281
|
for file in sources:
|
|
273
282
|
if file.module_name in final_filenames:
|
|
@@ -278,27 +287,31 @@ def build_index_and_filter_files(
|
|
|
278
287
|
# source_code += f"{file.source_code}\n\n"
|
|
279
288
|
temp_sources.append(file)
|
|
280
289
|
|
|
281
|
-
|
|
290
|
+
# 开启了裁剪,则需要做裁剪,不过目前只针对 quick filter 生效
|
|
282
291
|
if args.context_prune:
|
|
283
|
-
context_pruner = PruneContext(
|
|
292
|
+
context_pruner = PruneContext(
|
|
293
|
+
max_tokens=args.conversation_prune_safe_zone_tokens, args=args, llm=llm)
|
|
284
294
|
# 如果 file_positions 不为空,则通过 file_positions 来获取文件
|
|
285
295
|
if file_positions:
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
position_file_pairs = [(pos, file_path)
|
|
296
|
+
# 拿到位置列表,然后根据位置排序 得到 [(pos,file_path)]
|
|
297
|
+
# 将 [(pos,file_path)] 转换为 [file_path]
|
|
298
|
+
# 通过 [file_path] 顺序调整 temp_sources 的顺序
|
|
299
|
+
# MARK
|
|
300
|
+
# 将 file_positions 转换为 [(pos, file_path)] 的列表
|
|
301
|
+
position_file_pairs = [(pos, file_path)
|
|
302
|
+
for file_path, pos in file_positions.items()]
|
|
292
303
|
# 按位置排序
|
|
293
304
|
position_file_pairs.sort(key=lambda x: x[0])
|
|
294
305
|
# 提取排序后的文件路径列表
|
|
295
|
-
sorted_file_paths = [file_path for _,
|
|
306
|
+
sorted_file_paths = [file_path for _,
|
|
307
|
+
file_path in position_file_pairs]
|
|
296
308
|
# 根据 sorted_file_paths 重新排序 temp_sources
|
|
297
|
-
temp_sources.sort(key=lambda x: sorted_file_paths.index(
|
|
298
|
-
|
|
299
|
-
pruned_files = context_pruner.handle_overflow(temp_sources, [{"role":"user","content":args.query}], args.context_prune_strategy)
|
|
300
|
-
source_code_list.sources = pruned_files
|
|
309
|
+
temp_sources.sort(key=lambda x: sorted_file_paths.index(
|
|
310
|
+
x.module_name) if x.module_name in sorted_file_paths else len(sorted_file_paths))
|
|
301
311
|
|
|
312
|
+
pruned_files = context_pruner.handle_overflow(
|
|
313
|
+
temp_sources, [{"role": "user", "content": args.query}], args.context_prune_strategy)
|
|
314
|
+
source_code_list.sources = pruned_files
|
|
302
315
|
|
|
303
316
|
if args.request_id and not args.skip_events:
|
|
304
317
|
queue_communicate.send_event(
|
|
@@ -309,7 +322,7 @@ def build_index_and_filter_files(
|
|
|
309
322
|
(file.module_name, "") for file in source_code_list.sources
|
|
310
323
|
])
|
|
311
324
|
)
|
|
312
|
-
)
|
|
325
|
+
)
|
|
313
326
|
|
|
314
327
|
stats["final_files"] = len(source_code_list.sources)
|
|
315
328
|
phase_end = time.monotonic()
|
|
@@ -319,7 +332,7 @@ def build_index_and_filter_files(
|
|
|
319
332
|
total_end_time = time.monotonic()
|
|
320
333
|
total_time = total_end_time - total_start_time
|
|
321
334
|
stats["timings"]["total"] = total_time
|
|
322
|
-
|
|
335
|
+
|
|
323
336
|
# Calculate total filter time
|
|
324
337
|
total_filter_time = (
|
|
325
338
|
stats["timings"]["quick_filter"] +
|
|
@@ -354,7 +367,7 @@ def build_index_and_filter_files(
|
|
|
354
367
|
# summary,
|
|
355
368
|
# text_options={"justify": "left", "style": "bold white"},
|
|
356
369
|
# panel_options={
|
|
357
|
-
# "title": "Indexing and Filtering Summary",
|
|
370
|
+
# "title": "Indexing and Filtering Summary",
|
|
358
371
|
# "border_style": "bold blue",
|
|
359
372
|
# "padding": (1, 2),
|
|
360
373
|
# "expand": False
|
|
@@ -372,19 +385,34 @@ def build_index_and_filter_files(
|
|
|
372
385
|
})
|
|
373
386
|
)
|
|
374
387
|
)
|
|
375
|
-
|
|
388
|
+
|
|
389
|
+
get_event_manager(args.event_file).write_result(
|
|
390
|
+
EventContentCreator.create_result(
|
|
391
|
+
content=EventContentCreator.ResultContextUsedContent(
|
|
392
|
+
files=final_filenames,
|
|
393
|
+
title="Files Used as Context",
|
|
394
|
+
description=""
|
|
395
|
+
).to_dict()
|
|
396
|
+
),
|
|
397
|
+
metadata=EventMetadata(
|
|
398
|
+
action_file=args.file
|
|
399
|
+
).to_dict()
|
|
400
|
+
)
|
|
401
|
+
|
|
376
402
|
if args.file:
|
|
377
403
|
action_file_name = os.path.basename(args.file)
|
|
378
404
|
dynamic_urls = []
|
|
379
|
-
|
|
405
|
+
|
|
380
406
|
for file in source_code_list.sources:
|
|
381
407
|
dynamic_urls.append(file.module_name)
|
|
382
|
-
|
|
408
|
+
|
|
383
409
|
args.dynamic_urls = dynamic_urls
|
|
384
410
|
|
|
385
|
-
update_yaml_success = action_yml_file_manager.update_yaml_field(
|
|
386
|
-
|
|
411
|
+
update_yaml_success = action_yml_file_manager.update_yaml_field(
|
|
412
|
+
action_file_name, "dynamic_urls", args.dynamic_urls)
|
|
413
|
+
if not update_yaml_success:
|
|
387
414
|
printer = Printer()
|
|
388
|
-
printer.print_in_terminal(
|
|
389
|
-
|
|
390
|
-
|
|
415
|
+
printer.print_in_terminal(
|
|
416
|
+
"yaml_save_error", style="red", yaml_file=action_file_name)
|
|
417
|
+
|
|
418
|
+
return source_code_list
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import List, Union, Dict, Any, Optional
|
|
2
2
|
from pydantic import BaseModel
|
|
3
|
+
from autocoder.common.stream_out_type import IndexFilterStreamOutType
|
|
3
4
|
from autocoder.utils.auto_coder_utils.chat_stream_out import stream_out
|
|
4
5
|
from autocoder.common.utils_code_auto_generate import stream_chat_with_continue
|
|
5
6
|
from byzerllm.utils.str2model import to_model
|
|
@@ -24,6 +25,9 @@ from byzerllm.utils.client.code_utils import extract_code
|
|
|
24
25
|
import json
|
|
25
26
|
from autocoder.index.symbols_utils import extract_symbols
|
|
26
27
|
import os.path
|
|
28
|
+
from autocoder.events.event_manager_singleton import get_event_manager
|
|
29
|
+
from autocoder.events import event_content as EventContentCreator
|
|
30
|
+
from autocoder.events.event_types import EventMetadata
|
|
27
31
|
|
|
28
32
|
|
|
29
33
|
def get_file_path(file_path):
|
|
@@ -123,7 +127,10 @@ class QuickFilter():
|
|
|
123
127
|
model_name=model_name,
|
|
124
128
|
title=self.printer.get_message_from_key_with_format(
|
|
125
129
|
"quick_filter_title", model_name=model_name),
|
|
126
|
-
args=self.args
|
|
130
|
+
args=self.args,
|
|
131
|
+
extra_meta={
|
|
132
|
+
"stream_out_type": IndexFilterStreamOutType.FILE_NUMBER_LIST.value
|
|
133
|
+
}
|
|
127
134
|
)
|
|
128
135
|
file_number_list = to_model(full_response, FileNumberList)
|
|
129
136
|
|
|
@@ -153,6 +160,17 @@ class QuickFilter():
|
|
|
153
160
|
output_cost=total_output_cost,
|
|
154
161
|
model_names=model_name
|
|
155
162
|
)
|
|
163
|
+
|
|
164
|
+
get_event_manager(self.args.event_file).write_result(
|
|
165
|
+
EventContentCreator.create_result(content=EventContentCreator.ResultTokenStatContent(
|
|
166
|
+
model_name=model_name,
|
|
167
|
+
elapsed_time=0,
|
|
168
|
+
first_token_time=0,
|
|
169
|
+
input_tokens=last_meta.input_tokens_count,
|
|
170
|
+
output_tokens=last_meta.generated_tokens_count,
|
|
171
|
+
input_cost=total_input_cost,
|
|
172
|
+
output_cost=total_output_cost
|
|
173
|
+
).to_dict()))
|
|
156
174
|
else:
|
|
157
175
|
# 其他chunks直接使用with_llm
|
|
158
176
|
meta_holder = MetaHolder()
|
|
@@ -178,6 +196,16 @@ class QuickFilter():
|
|
|
178
196
|
model_names=model_name,
|
|
179
197
|
elapsed_time=f"{end_time - start_time:.2f}"
|
|
180
198
|
)
|
|
199
|
+
get_event_manager(self.args.event_file).write_result(
|
|
200
|
+
EventContentCreator.create_result(content=EventContentCreator.ResultTokenStatContent(
|
|
201
|
+
model_name=model_name,
|
|
202
|
+
elapsed_time=end_time - start_time,
|
|
203
|
+
first_token_time=0,
|
|
204
|
+
input_tokens=meta_dict.get("input_tokens_count", 0),
|
|
205
|
+
output_tokens=meta_dict.get("generated_tokens_count", 0),
|
|
206
|
+
input_cost=total_input_cost,
|
|
207
|
+
output_cost=total_output_cost
|
|
208
|
+
).to_dict()))
|
|
181
209
|
|
|
182
210
|
if file_number_list:
|
|
183
211
|
for index,file_number in enumerate(file_number_list.file_list):
|
|
@@ -475,7 +503,10 @@ class QuickFilter():
|
|
|
475
503
|
title=self.printer.get_message_from_key_with_format(
|
|
476
504
|
"quick_filter_title", model_name=model_name),
|
|
477
505
|
args=self.args,
|
|
478
|
-
display_func=extract_file_number_list
|
|
506
|
+
display_func=extract_file_number_list,
|
|
507
|
+
extra_meta={
|
|
508
|
+
"stream_out_type": IndexFilterStreamOutType.FILE_NUMBER_LIST.value
|
|
509
|
+
}
|
|
479
510
|
)
|
|
480
511
|
# 解析结果
|
|
481
512
|
file_number_list = to_model(full_response, FileNumberList)
|
|
@@ -510,6 +541,16 @@ class QuickFilter():
|
|
|
510
541
|
model_names=model_name,
|
|
511
542
|
speed=f"{speed:.2f}"
|
|
512
543
|
)
|
|
544
|
+
get_event_manager(self.args.event_file).write_result(
|
|
545
|
+
EventContentCreator.create_result(content=EventContentCreator.ResultTokenStatContent(
|
|
546
|
+
model_name=model_name,
|
|
547
|
+
elapsed_time=end_time - start_time,
|
|
548
|
+
input_tokens=last_meta.input_tokens_count,
|
|
549
|
+
output_tokens=last_meta.generated_tokens_count,
|
|
550
|
+
input_cost=total_input_cost,
|
|
551
|
+
output_cost=total_output_cost,
|
|
552
|
+
speed=speed
|
|
553
|
+
).to_dict()))
|
|
513
554
|
|
|
514
555
|
except Exception as e:
|
|
515
556
|
self.printer.print_in_terminal(
|
|
@@ -737,7 +778,10 @@ class QuickFilter():
|
|
|
737
778
|
title=self.printer.get_message_from_key_with_format(
|
|
738
779
|
"super_big_filter_title", model_name=model_name),
|
|
739
780
|
args=self.args,
|
|
740
|
-
display_func=extract_file_number_list
|
|
781
|
+
display_func=extract_file_number_list,
|
|
782
|
+
extra_meta={
|
|
783
|
+
"stream_out_type": IndexFilterStreamOutType.FILE_NUMBER_LIST.value
|
|
784
|
+
}
|
|
741
785
|
)
|
|
742
786
|
|
|
743
787
|
# 解析结果
|
|
@@ -773,6 +817,18 @@ class QuickFilter():
|
|
|
773
817
|
speed=f"{speed:.2f}",
|
|
774
818
|
chunk_index=chunk_index
|
|
775
819
|
)
|
|
820
|
+
|
|
821
|
+
get_event_manager(self.args.event_file).write_result(
|
|
822
|
+
EventContentCreator.create_result(content=EventContentCreator.ResultTokenStatContent(
|
|
823
|
+
model_name=model_name,
|
|
824
|
+
elapsed_time=end_time - start_time,
|
|
825
|
+
input_tokens=last_meta.input_tokens_count,
|
|
826
|
+
output_tokens=last_meta.generated_tokens_count,
|
|
827
|
+
input_cost=total_input_cost,
|
|
828
|
+
output_cost=total_output_cost,
|
|
829
|
+
speed=speed
|
|
830
|
+
).to_dict()))
|
|
831
|
+
|
|
776
832
|
else:
|
|
777
833
|
# 非UI模式,直接使用LLM处理
|
|
778
834
|
meta_holder = MetaHolder()
|
|
@@ -797,6 +853,18 @@ class QuickFilter():
|
|
|
797
853
|
elapsed_time=f"{end_time - start_time:.2f}",
|
|
798
854
|
chunk_index=chunk_index
|
|
799
855
|
)
|
|
856
|
+
|
|
857
|
+
get_event_manager(self.args.event_file).write_result(
|
|
858
|
+
EventContentCreator.create_result(content=EventContentCreator.ResultTokenStatContent(
|
|
859
|
+
model_name=model_name,
|
|
860
|
+
elapsed_time=end_time - start_time,
|
|
861
|
+
input_tokens=meta_dict.get("input_tokens_count", 0),
|
|
862
|
+
output_tokens=meta_dict.get("generated_tokens_count", 0),
|
|
863
|
+
input_cost=total_input_cost,
|
|
864
|
+
output_cost=total_output_cost,
|
|
865
|
+
speed=speed
|
|
866
|
+
).to_dict()))
|
|
867
|
+
|
|
800
868
|
|
|
801
869
|
# 构建返回结果
|
|
802
870
|
files = {}
|
autocoder/run_context.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module providing a singleton class to track run context (terminal or web mode).
|
|
3
|
+
"""
|
|
4
|
+
from enum import Enum, auto
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RunMode(Enum):
|
|
9
|
+
"""Enum representing different run modes for Auto-Coder."""
|
|
10
|
+
TERMINAL = auto()
|
|
11
|
+
WEB = auto()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RunContext:
|
|
15
|
+
"""
|
|
16
|
+
Singleton class to track whether Auto-Coder is running in terminal or web mode.
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
from autocoder.run_context import get_run_context
|
|
20
|
+
|
|
21
|
+
# Get current mode
|
|
22
|
+
context = get_run_context()
|
|
23
|
+
if context.mode == RunMode.WEB:
|
|
24
|
+
# Do web-specific things
|
|
25
|
+
|
|
26
|
+
# Set mode
|
|
27
|
+
context.set_mode(RunMode.WEB)
|
|
28
|
+
"""
|
|
29
|
+
_instance: Optional['RunContext'] = None
|
|
30
|
+
|
|
31
|
+
def __new__(cls):
|
|
32
|
+
if cls._instance is None:
|
|
33
|
+
cls._instance = super(RunContext, cls).__new__(cls)
|
|
34
|
+
cls._instance._mode = RunMode.TERMINAL # Default to terminal mode
|
|
35
|
+
return cls._instance
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def mode(self) -> RunMode:
|
|
39
|
+
"""Get the current run mode."""
|
|
40
|
+
return self._mode
|
|
41
|
+
|
|
42
|
+
def set_mode(self, mode: RunMode) -> None:
|
|
43
|
+
"""Set the current run mode."""
|
|
44
|
+
self._mode = mode
|
|
45
|
+
|
|
46
|
+
def is_terminal(self) -> bool:
|
|
47
|
+
"""Check if running in terminal mode."""
|
|
48
|
+
return self._mode == RunMode.TERMINAL
|
|
49
|
+
|
|
50
|
+
def is_web(self) -> bool:
|
|
51
|
+
"""Check if running in web mode."""
|
|
52
|
+
return self._mode == RunMode.WEB
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_run_context() -> RunContext:
|
|
56
|
+
"""
|
|
57
|
+
Get the singleton RunContext instance.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
RunContext: The singleton instance of RunContext
|
|
61
|
+
"""
|
|
62
|
+
return RunContext()
|
|
@@ -7,12 +7,16 @@ from rich.layout import Layout
|
|
|
7
7
|
from threading import Thread, Lock
|
|
8
8
|
from queue import Queue, Empty
|
|
9
9
|
from typing import Generator, List, Dict, Any, Optional, Tuple, Callable
|
|
10
|
+
from autocoder.events.event_types import EventType
|
|
10
11
|
from autocoder.utils.request_queue import RequestValue, RequestOption, StreamValue
|
|
11
12
|
from autocoder.utils.request_queue import request_queue
|
|
12
13
|
import time
|
|
13
14
|
from byzerllm.utils.types import SingleOutputMeta
|
|
14
15
|
from autocoder.common import AutoCoderArgs
|
|
15
16
|
from autocoder.common.global_cancel import global_cancel
|
|
17
|
+
from autocoder.events.event_manager_singleton import get_event_manager
|
|
18
|
+
from autocoder.events import event_content as EventContentCreator
|
|
19
|
+
from autocoder.events.event_types import EventMetadata
|
|
16
20
|
|
|
17
21
|
MAX_HISTORY_LINES = 40 # 最大保留历史行数
|
|
18
22
|
|
|
@@ -150,7 +154,8 @@ def stream_out(
|
|
|
150
154
|
title: Optional[str] = None,
|
|
151
155
|
final_title: Optional[str] = None,
|
|
152
156
|
args: Optional[AutoCoderArgs] = None,
|
|
153
|
-
display_func: Optional[Callable] = None
|
|
157
|
+
display_func: Optional[Callable] = None,
|
|
158
|
+
extra_meta: Dict[str, Any] = {}
|
|
154
159
|
) -> Tuple[str, Optional[SingleOutputMeta]]:
|
|
155
160
|
"""
|
|
156
161
|
处理流式输出事件并在终端中展示
|
|
@@ -184,6 +189,7 @@ def stream_out(
|
|
|
184
189
|
final_panel_title = final_title if final_title is not None else title
|
|
185
190
|
first_token_time = 0.0
|
|
186
191
|
first_token_time_start = time.time()
|
|
192
|
+
sequence = 0
|
|
187
193
|
try:
|
|
188
194
|
with Live(
|
|
189
195
|
Panel("", title=panel_title, border_style="green"),
|
|
@@ -246,6 +252,21 @@ def stream_out(
|
|
|
246
252
|
# 构建显示内容 = 历史行 + 当前行
|
|
247
253
|
display_content = "\n".join(lines_buffer[-MAX_HISTORY_LINES:] + [current_line])
|
|
248
254
|
|
|
255
|
+
|
|
256
|
+
content = EventContentCreator.create_stream_thinking(
|
|
257
|
+
content=display_delta,
|
|
258
|
+
sequence=sequence
|
|
259
|
+
)
|
|
260
|
+
get_event_manager(args.event_file).write_stream(content.to_dict(),
|
|
261
|
+
metadata=EventMetadata(
|
|
262
|
+
stream_out_type=extra_meta.get("stream_out_type", ""),
|
|
263
|
+
is_streaming=True,
|
|
264
|
+
output="delta",
|
|
265
|
+
action_file=args.file
|
|
266
|
+
).to_dict()
|
|
267
|
+
)
|
|
268
|
+
sequence += 1
|
|
269
|
+
|
|
249
270
|
if request_id and request_queue:
|
|
250
271
|
request_queue.add_request(
|
|
251
272
|
request_id,
|
|
@@ -273,6 +294,16 @@ def stream_out(
|
|
|
273
294
|
if display_func:
|
|
274
295
|
final_display_content = display_func(assistant_response)
|
|
275
296
|
|
|
297
|
+
content = EventContentCreator.create_markdown_result(
|
|
298
|
+
content=final_display_content
|
|
299
|
+
)
|
|
300
|
+
get_event_manager(args.event_file).write_result(content.to_dict(), metadata=EventMetadata(
|
|
301
|
+
stream_out_type=extra_meta.get("stream_out_type", ""),
|
|
302
|
+
is_streaming=True,
|
|
303
|
+
output="result",
|
|
304
|
+
action_file=args.file
|
|
305
|
+
).to_dict())
|
|
306
|
+
|
|
276
307
|
live.update(
|
|
277
308
|
Panel(
|
|
278
309
|
Markdown(final_display_content),
|
autocoder/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.303"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|