auto-coder 0.1.259__py3-none-any.whl → 0.1.261__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.

Files changed (36) hide show
  1. {auto_coder-0.1.259.dist-info → auto_coder-0.1.261.dist-info}/METADATA +1 -1
  2. {auto_coder-0.1.259.dist-info → auto_coder-0.1.261.dist-info}/RECORD +36 -27
  3. autocoder/agent/auto_review_commit.py +51 -24
  4. autocoder/auto_coder.py +24 -1
  5. autocoder/chat_auto_coder.py +377 -399
  6. autocoder/chat_auto_coder_lang.py +20 -0
  7. autocoder/commands/__init__.py +0 -0
  8. autocoder/commands/auto_command.py +1174 -0
  9. autocoder/commands/tools.py +533 -0
  10. autocoder/common/__init__.py +8 -0
  11. autocoder/common/auto_coder_lang.py +61 -8
  12. autocoder/common/auto_configure.py +304 -0
  13. autocoder/common/code_auto_merge.py +2 -2
  14. autocoder/common/code_auto_merge_diff.py +2 -2
  15. autocoder/common/code_auto_merge_editblock.py +2 -2
  16. autocoder/common/code_auto_merge_strict_diff.py +2 -2
  17. autocoder/common/code_modification_ranker.py +8 -7
  18. autocoder/common/command_completer.py +557 -0
  19. autocoder/common/conf_validator.py +245 -0
  20. autocoder/common/conversation_pruner.py +131 -0
  21. autocoder/common/git_utils.py +82 -1
  22. autocoder/common/index_import_export.py +101 -0
  23. autocoder/common/result_manager.py +115 -0
  24. autocoder/common/shells.py +22 -6
  25. autocoder/common/utils_code_auto_generate.py +2 -2
  26. autocoder/dispacher/actions/action.py +45 -4
  27. autocoder/dispacher/actions/plugins/action_regex_project.py +13 -1
  28. autocoder/index/filter/quick_filter.py +22 -7
  29. autocoder/utils/auto_coder_utils/chat_stream_out.py +13 -6
  30. autocoder/utils/project_structure.py +15 -0
  31. autocoder/utils/thread_utils.py +4 -0
  32. autocoder/version.py +1 -1
  33. {auto_coder-0.1.259.dist-info → auto_coder-0.1.261.dist-info}/LICENSE +0 -0
  34. {auto_coder-0.1.259.dist-info → auto_coder-0.1.261.dist-info}/WHEEL +0 -0
  35. {auto_coder-0.1.259.dist-info → auto_coder-0.1.261.dist-info}/entry_points.txt +0 -0
  36. {auto_coder-0.1.259.dist-info → auto_coder-0.1.261.dist-info}/top_level.txt +0 -0
@@ -9,6 +9,8 @@ from rich.panel import Panel
9
9
  from rich.text import Text
10
10
  from rich.live import Live
11
11
 
12
+ from autocoder.common.result_manager import ResultManager
13
+
12
14
  def get_terminal_name() -> str:
13
15
  """
14
16
  获取当前终端名称(自动适配 Windows/Linux/Mac)
@@ -139,6 +141,7 @@ def execute_shell_command(command: str):
139
141
  encoding (str, optional): Override default encoding. Defaults to None.
140
142
  """
141
143
  console = Console()
144
+ result_manager = ResultManager()
142
145
  try:
143
146
  # Get terminal encoding
144
147
  encoding = get_terminal_encoding()
@@ -199,7 +202,13 @@ def execute_shell_command(command: str):
199
202
  output.append(safe_decode(remaining_out, encoding))
200
203
  if remaining_err:
201
204
  output.append(f"ERROR: {safe_decode(remaining_err, encoding)}")
202
-
205
+
206
+ result_manager.add_result(content="\n".join(output),meta={
207
+ "action": "execute_shell_command",
208
+ "input": {
209
+ "command": command
210
+ }
211
+ })
203
212
  # Show final output
204
213
  console.print(
205
214
  Panel(
@@ -210,16 +219,23 @@ def execute_shell_command(command: str):
210
219
  )
211
220
  )
212
221
 
213
- if process.returncode != 0:
214
- console.print(
215
- f"[bold red]Command failed with code {process.returncode}[/bold red]"
216
- )
217
-
218
222
  except FileNotFoundError:
223
+ result_manager.add_result(content=f"[bold red]Command not found:[/bold red] [yellow]{command}[/yellow]",meta={
224
+ "action": "execute_shell_command",
225
+ "input": {
226
+ "command": command
227
+ }
228
+ })
219
229
  console.print(
220
230
  f"[bold red]Command not found:[/bold red] [yellow]{command}[/yellow]"
221
231
  )
222
232
  except Exception as e:
233
+ result_manager.add_result(content=f"[bold red]Unexpected error:[/bold red] [yellow]{str(e)}[/yellow]",meta={
234
+ "action": "execute_shell_command",
235
+ "input": {
236
+ "command": command
237
+ }
238
+ })
223
239
  console.print(
224
240
  f"[bold red]Unexpected error:[/bold red] [yellow]{str(e)}[/yellow]"
225
241
  )
@@ -1,5 +1,5 @@
1
1
  from byzerllm import ByzerLLM,SimpleByzerLLM
2
- from typing import Generator, List, Any, Union
2
+ from typing import Generator, List, Any, Union, Optional, Callable
3
3
  from pydantic import BaseModel
4
4
  from loguru import logger
5
5
 
@@ -41,7 +41,7 @@ def chat_with_continue(llm: Union[ByzerLLM,SimpleByzerLLM], conversations: List[
41
41
  def stream_chat_with_continue(
42
42
  llm: Union[ByzerLLM, SimpleByzerLLM],
43
43
  conversations: List[dict],
44
- llm_config: dict
44
+ llm_config: dict
45
45
  ) -> Generator[Any, None, None]:
46
46
  """
47
47
  流式处理并继续生成内容,直到完成。
@@ -29,6 +29,7 @@ from autocoder.common.printer import Printer
29
29
  from autocoder.utils.llms import get_llm_names
30
30
  from autocoder.privacy.model_filter import ModelPathFilter
31
31
  from autocoder.common import SourceCodeList
32
+ from autocoder.common.global_cancel import global_cancel
32
33
 
33
34
 
34
35
  class BaseAction:
@@ -106,6 +107,10 @@ class ActionTSProject(BaseAction):
106
107
  f"Content(send to model) is {content_length} tokens, which is larger than the maximum input length {self.args.model_max_input_length}"
107
108
  )
108
109
 
110
+ if global_cancel.requested:
111
+ printer = Printer()
112
+ raise Exception(printer.get_message_from_key("generation_cancelled"))
113
+
109
114
  if args.execute:
110
115
  self.printer.print_in_terminal("code_generation_start")
111
116
  start_time = time.time()
@@ -145,8 +150,14 @@ class ActionTSProject(BaseAction):
145
150
  input_cost=input_tokens_cost,
146
151
  output_cost=generated_tokens_cost,
147
152
  speed=round(speed, 2),
148
- model_names=model_names
153
+ model_names=model_names,
154
+ sampling_count=len(generate_result.contents)
149
155
  )
156
+
157
+ if global_cancel.requested:
158
+ printer = Printer()
159
+ raise Exception(printer.get_message_from_key("generation_cancelled"))
160
+
150
161
  merge_result = None
151
162
  if args.execute and args.auto_merge:
152
163
  self.printer.print_in_terminal("code_merge_start")
@@ -206,6 +217,10 @@ class ActionPyScriptProject(BaseAction):
206
217
 
207
218
  def process_content(self, source_code_list: SourceCodeList):
208
219
  args = self.args
220
+ if global_cancel.requested:
221
+ printer = Printer()
222
+ raise Exception(printer.get_message_from_key("generation_cancelled"))
223
+
209
224
  if args.execute:
210
225
  self.printer.print_in_terminal("code_generation_start")
211
226
  start_time = time.time()
@@ -245,8 +260,14 @@ class ActionPyScriptProject(BaseAction):
245
260
  input_cost=input_tokens_cost,
246
261
  output_cost=generated_tokens_cost,
247
262
  speed=round(speed, 2),
248
- model_names=model_names
263
+ model_names=model_names,
264
+ sampling_count=len(generate_result.contents)
249
265
  )
266
+
267
+ if global_cancel.requested:
268
+ printer = Printer()
269
+ raise Exception(printer.get_message_from_key("generation_cancelled"))
270
+
250
271
  merge_result = None
251
272
  if args.execute and args.auto_merge:
252
273
  self.printer.print_in_terminal("code_merge_start")
@@ -329,6 +350,10 @@ class ActionPyProject(BaseAction):
329
350
  content_length=content_length,
330
351
  max_length=self.args.model_max_input_length
331
352
  )
353
+
354
+ if global_cancel.requested:
355
+ printer = Printer()
356
+ raise Exception(printer.get_message_from_key("generation_cancelled"))
332
357
 
333
358
  if args.execute:
334
359
  self.printer.print_in_terminal("code_generation_start")
@@ -370,8 +395,14 @@ class ActionPyProject(BaseAction):
370
395
  input_cost=input_tokens_cost,
371
396
  output_cost=generated_tokens_cost,
372
397
  speed=round(speed, 2),
373
- model_names=model_names
398
+ model_names=model_names,
399
+ sampling_count=len(generate_result.contents)
374
400
  )
401
+
402
+ if global_cancel.requested:
403
+ printer = Printer()
404
+ raise Exception(printer.get_message_from_key("generation_cancelled"))
405
+
375
406
  merge_result = None
376
407
  if args.execute and args.auto_merge:
377
408
  self.printer.print_in_terminal("code_merge_start")
@@ -446,6 +477,10 @@ class ActionSuffixProject(BaseAction):
446
477
  f"Content(send to model) is {content_length} tokens, which is larger than the maximum input length {self.args.model_max_input_length}"
447
478
  )
448
479
 
480
+ if global_cancel.requested:
481
+ printer = Printer()
482
+ raise Exception(printer.get_message_from_key("generation_cancelled"))
483
+
449
484
  if args.execute:
450
485
  self.printer.print_in_terminal("code_generation_start")
451
486
  start_time = time.time()
@@ -485,8 +520,14 @@ class ActionSuffixProject(BaseAction):
485
520
  input_cost=input_tokens_cost,
486
521
  output_cost=generated_tokens_cost,
487
522
  speed=round(speed, 2),
488
- model_names=model_names
523
+ model_names=model_names,
524
+ sampling_count=len(generate_result.contents)
489
525
  )
526
+
527
+ if global_cancel.requested:
528
+ printer = Printer()
529
+ raise Exception(printer.get_message_from_key("generation_cancelled") )
530
+
490
531
  merge_result = None
491
532
  if args.execute and args.auto_merge:
492
533
  self.printer.print_in_terminal("code_merge_start")
@@ -16,6 +16,7 @@ from autocoder.common.printer import Printer
16
16
  import time
17
17
  from autocoder.utils.llms import get_llm_names
18
18
  from autocoder.common import SourceCodeList
19
+ from autocoder.common.global_cancel import global_cancel
19
20
  from loguru import logger
20
21
  class ActionRegexProject:
21
22
  def __init__(
@@ -61,6 +62,11 @@ class ActionRegexProject:
61
62
  content = content[: self.args.model_max_input_length]
62
63
 
63
64
  start_time = time.time()
65
+
66
+ if global_cancel.requested:
67
+ printer = Printer()
68
+ raise Exception(printer.get_message_from_key("generation_cancelled"))
69
+
64
70
  if args.execute:
65
71
  self.printer.print_in_terminal("code_generation_start")
66
72
 
@@ -100,8 +106,14 @@ class ActionRegexProject:
100
106
  input_cost=input_tokens_cost,
101
107
  output_cost=generated_tokens_cost,
102
108
  speed=round(speed, 2),
103
- model_names=model_names
109
+ model_names=model_names,
110
+ sampling_count=len(generate_result.contents)
104
111
  )
112
+
113
+ if global_cancel.requested:
114
+ printer = Printer()
115
+ raise Exception(printer.get_message_from_key("generation_cancelled"))
116
+
105
117
  merge_result = None
106
118
  if args.execute and args.auto_merge:
107
119
  self.printer.print_in_terminal("code_merge_start")
@@ -19,6 +19,7 @@ from concurrent.futures import ThreadPoolExecutor
19
19
  from byzerllm import MetaHolder
20
20
 
21
21
  from autocoder.utils.llms import get_llm_names, get_model_info
22
+ from loguru import logger
22
23
 
23
24
 
24
25
  def get_file_path(file_path):
@@ -229,7 +230,8 @@ class QuickFilter():
229
230
  {{ content }}
230
231
  </index>
231
232
 
232
- 索引文件包含文件序号(##[]括起来的部分),文件路径,文件符号信息等。
233
+ 索引文件包含文件序号(##[]括起来的部分),文件路径,文件符号信息等。
234
+
233
235
  下面是用户的查询需求:
234
236
 
235
237
  <query>
@@ -248,16 +250,18 @@ class QuickFilter():
248
250
  }
249
251
  ```
250
252
 
251
- 特别注意
252
- 1. 如果用户的query里 @文件 或者 @@符号,那么被@的文件或者@@的符号必须要返回,并且查看他们依赖的文件是否相关。
253
+ 特别注意
254
+ 1. 如果用户的query里 @文件 或者 @@符号,那么被@的文件或者@@的符号必须要返回,并且尝试通过索引文件诸如导入语句等信息找到这些文件依赖的其他文件,再分析这些文件是否需要提供才能满足后续编码。
253
255
  2. 如果 query 里是一段历史对话,那么对话里的内容提及的文件路径必须要返回。
254
- 3. json格式数据不允许有注释
256
+ 3. 想想,如果是你需要修改代码,然后满足这个需求,根据索引文件,你希望查看哪些文件,修改哪些文件,然后返回这些文件。
257
+ 4. 返回的 json格式数据不允许有注释
255
258
  '''
259
+
256
260
  file_meta_str = "\n".join(
257
261
  [f"##[{index}]{item.module_name}\n{item.symbols}" for index, item in enumerate(file_meta_list)])
258
262
  context = {
259
263
  "content": file_meta_str,
260
- "query": query
264
+ "query": query
261
265
  }
262
266
  return context
263
267
 
@@ -308,13 +312,22 @@ class QuickFilter():
308
312
  {}
309
313
  )
310
314
 
315
+ def extract_file_number_list(content: str) -> str:
316
+ try:
317
+ v = to_model(content, FileNumberList)
318
+ return "\n".join([index_items[file_number].module_name for file_number in v.file_list])
319
+ except Exception as e:
320
+ logger.error(f"Error extracting file number list: {e}")
321
+ return content
322
+
311
323
  # 获取完整响应
312
324
  full_response, last_meta = stream_out(
313
325
  stream_generator,
314
326
  model_name=model_name,
315
327
  title=self.printer.get_message_from_key_with_format(
316
328
  "quick_filter_title", model_name=model_name),
317
- args=self.args
329
+ args=self.args,
330
+ display_func=extract_file_number_list
318
331
  )
319
332
  # 解析结果
320
333
  file_number_list = to_model(full_response, FileNumberList)
@@ -335,6 +348,7 @@ class QuickFilter():
335
348
  # 四舍五入到4位小数
336
349
  total_input_cost = round(total_input_cost, 4)
337
350
  total_output_cost = round(total_output_cost, 4)
351
+ speed = last_meta.generated_tokens_count / (end_time - start_time)
338
352
 
339
353
  # 打印 token 统计信息和成本
340
354
  self.printer.print_in_terminal(
@@ -345,7 +359,8 @@ class QuickFilter():
345
359
  output_tokens=last_meta.generated_tokens_count,
346
360
  input_cost=total_input_cost,
347
361
  output_cost=total_output_cost,
348
- model_names=model_name
362
+ model_names=model_name,
363
+ speed=f"{speed:.2f}"
349
364
  )
350
365
 
351
366
  except Exception as e:
@@ -6,7 +6,7 @@ from rich.markdown import Markdown
6
6
  from rich.layout import Layout
7
7
  from threading import Thread, Lock
8
8
  from queue import Queue, Empty
9
- from typing import Generator, List, Dict, Any, Optional, Tuple, Literal
9
+ from typing import Generator, List, Dict, Any, Optional, Tuple, Callable
10
10
  from autocoder.utils.request_queue import RequestValue, RequestOption, StreamValue
11
11
  from autocoder.utils.request_queue import request_queue
12
12
  import time
@@ -148,7 +148,9 @@ def stream_out(
148
148
  console: Optional[Console] = None,
149
149
  model_name: Optional[str] = None,
150
150
  title: Optional[str] = None,
151
- args: Optional[AutoCoderArgs] = None
151
+ final_title: Optional[str] = None,
152
+ args: Optional[AutoCoderArgs] = None,
153
+ display_func: Optional[Callable] = None
152
154
  ) -> Tuple[str, Optional[SingleOutputMeta]]:
153
155
  """
154
156
  处理流式输出事件并在终端中展示
@@ -179,6 +181,7 @@ def stream_out(
179
181
  assistant_response = ""
180
182
  last_meta = None
181
183
  panel_title = title if title is not None else f"Response[ {model_name} ]"
184
+ final_panel_title = final_title if final_title is not None else title
182
185
  first_token_time = 0.0
183
186
  first_token_time_start = time.time()
184
187
  try:
@@ -250,8 +253,8 @@ def stream_out(
250
253
  value=StreamValue(value=[content]),
251
254
  status=RequestOption.RUNNING,
252
255
  ),
253
- )
254
-
256
+ )
257
+
255
258
  live.update(
256
259
  Panel(
257
260
  Markdown(display_content),
@@ -266,10 +269,14 @@ def stream_out(
266
269
  lines_buffer.append(current_line)
267
270
 
268
271
  # 最终显示结果
272
+ final_display_content = assistant_response
273
+ if display_func:
274
+ final_display_content = display_func(assistant_response)
275
+
269
276
  live.update(
270
277
  Panel(
271
- Markdown(assistant_response),
272
- title=f"Final {panel_title}",
278
+ Markdown(final_display_content),
279
+ title=f"{final_panel_title}",
273
280
  border_style="blue"
274
281
  )
275
282
  )
@@ -0,0 +1,15 @@
1
+ from autocoder.pyproject import PyProject
2
+ from autocoder.tsproject import TSProject
3
+ from autocoder.suffixproject import SuffixProject
4
+ from autocoder.common import AutoCoderArgs
5
+ import byzerllm
6
+ from typing import Union
7
+
8
+ def get_project_structure(args:AutoCoderArgs, llm:Union[byzerllm.ByzerLLM, byzerllm.SimpleByzerLLM]):
9
+ if args.project_type == "ts":
10
+ pp = TSProject(args=args, llm=llm)
11
+ elif args.project_type == "py":
12
+ pp = PyProject(args=args, llm=llm)
13
+ else:
14
+ pp = SuffixProject(args=args, llm=llm, file_filter=None)
15
+ return pp.get_tree_like_directory_structure()
@@ -176,6 +176,7 @@ def run_in_raw_thread():
176
176
  exception = []
177
177
  def worker():
178
178
  try:
179
+ # global_cancel.reset()
179
180
  ret = func(*args, **kwargs)
180
181
  result.append(ret)
181
182
  global_cancel.reset()
@@ -196,6 +197,9 @@ def run_in_raw_thread():
196
197
  except KeyboardInterrupt:
197
198
  global_cancel.set()
198
199
  raise KeyboardInterrupt("Task was cancelled by user")
200
+ except Exception as e:
201
+ global_cancel.reset()
202
+ raise
199
203
 
200
204
  return wrapper
201
205
  return decorator
autocoder/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.259"
1
+ __version__ = "0.1.261"