autocoder-nano 0.1.35__py3-none-any.whl → 0.1.37__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.
@@ -10,11 +10,15 @@ import uuid
10
10
 
11
11
  from autocoder_nano.agent.agentic_edit import AgenticEdit
12
12
  from autocoder_nano.agent.agentic_edit_types import AgenticEditRequest
13
+ from autocoder_nano.chat import stream_chat_display
13
14
  from autocoder_nano.edit import Dispacher
14
15
  from autocoder_nano.helper import show_help
15
- from autocoder_nano.index.entry import build_index_and_filter_files
16
- from autocoder_nano.index.index_manager import IndexManager
17
- from autocoder_nano.index.symbols_utils import extract_symbols
16
+ from autocoder_nano.project import project_source
17
+ from autocoder_nano.index import (index_export, index_import, index_build,
18
+ index_build_and_filter, extract_symbols)
19
+ # from autocoder_nano.index.entry import build_index_and_filter_files
20
+ # from autocoder_nano.index.index_manager import IndexManager
21
+ # from autocoder_nano.index.symbols_utils import extract_symbols
18
22
  from autocoder_nano.llm_client import AutoLLM
19
23
  from autocoder_nano.rules.rules_learn import AutoRulesLearn
20
24
  from autocoder_nano.utils.completer_utils import CommandCompleter
@@ -25,7 +29,7 @@ from autocoder_nano.templates import create_actions
25
29
  from autocoder_nano.git_utils import (repo_init, commit_changes, revert_changes,
26
30
  get_uncommitted_changes, generate_commit_message)
27
31
  from autocoder_nano.sys_utils import default_exclude_dirs, detect_env
28
- from autocoder_nano.project import PyProject, SuffixProject
32
+ # from autocoder_nano.project import PyProject, SuffixProject, project_source
29
33
  from autocoder_nano.utils.printer_utils import Printer
30
34
 
31
35
  import yaml
@@ -316,119 +320,13 @@ def exclude_files(query: str):
316
320
 
317
321
  def index_command(llm):
318
322
  args = get_final_config(query="", delete_execute_file=True)
319
-
320
- source_dir = os.path.abspath(args.source_dir)
321
- printer.print_text(f"开始对目录 {source_dir} 中的源代码进行索引", style="green")
322
- if args.project_type == "py":
323
- pp = PyProject(llm=llm, args=args)
324
- else:
325
- pp = SuffixProject(llm=llm, args=args)
326
- pp.run()
327
- _sources = pp.sources
328
- index_manager = IndexManager(args=args, source_codes=_sources, llm=llm)
329
- index_manager.build_index()
330
-
331
-
332
- def index_export(export_path: str) -> bool:
333
- try:
334
- index_path = os.path.join(project_root, ".auto-coder", "index.json")
335
- if not os.path.exists(index_path):
336
- printer.print_text(Text(f"索引文件不存在. ", style="bold red"))
337
- return False
338
-
339
- with open(index_path, "r", encoding="utf-8") as f:
340
- index_data = json.load(f)
341
-
342
- converted_data = {}
343
- for abs_path, data in index_data.items():
344
- try:
345
- rel_path = os.path.relpath(abs_path, project_root)
346
- data["module_name"] = rel_path
347
- converted_data[rel_path] = data
348
- except ValueError:
349
- printer.print_text(Text(f"索引转换路径失败. ", style="dim yellow"))
350
- converted_data[abs_path] = data
351
-
352
- export_file = os.path.join(export_path, "index.json")
353
- with open(export_file, "w", encoding="utf-8") as f:
354
- json.dump(converted_data, f, indent=2)
355
- printer.print_text(Text(f"索引文件导出成功. ", style="bold green"))
356
- return True
357
- except Exception as err:
358
- printer.print_text(Text(f"索引文件导出失败: {err}", style="bold red"))
359
- return False
360
-
361
-
362
- def index_import(import_path: str):
363
- try:
364
- import_file = os.path.join(import_path, "index.json")
365
- if not os.path.exists(import_file):
366
- printer.print_text(Text(f"导入索引文件不存在", style="bold red"))
367
- return False
368
- with open(import_file, "r", encoding="utf-8") as f:
369
- index_data = json.load(f)
370
- converted_data = {}
371
- for rel_path, data in index_data.items():
372
- try:
373
- abs_path = os.path.join(project_root, rel_path)
374
- data["module_name"] = abs_path
375
- converted_data[abs_path] = data
376
- except Exception as err:
377
- printer.print_text(Text(f"{rel_path} 索引转换路径失败: {err}", style="dim yellow"))
378
- converted_data[rel_path] = data
379
- # Backup existing index
380
- index_path = os.path.join(project_root, ".auto-coder", "index.json")
381
- if os.path.exists(index_path):
382
- printer.print_text(Text(f"原索引文件不存在", style="bold yellow"))
383
- backup_path = index_path + ".bak"
384
- shutil.copy2(index_path, backup_path)
385
-
386
- # Write new index
387
- with open(index_path, "w", encoding="utf-8") as f:
388
- json.dump(converted_data, f, indent=2)
389
- return True
390
- except Exception as err:
391
- printer.print_text(Text(f"索引文件导入失败: {err}", style="bold red"))
392
- return False
323
+ index_build(llm=llm, args=args, sources_codes=project_source(source_llm=llm, args=args))
324
+ return
393
325
 
394
326
 
395
327
  def index_query_command(query: str, llm: AutoLLM):
396
328
  args = get_final_config(query=query, delete_execute_file=True)
397
-
398
- # args.query = query
399
- if args.project_type == "py":
400
- pp = PyProject(llm=llm, args=args)
401
- else:
402
- pp = SuffixProject(llm=llm, args=args)
403
- pp.run()
404
- _sources = pp.sources
405
-
406
- final_files = []
407
- index_manager = IndexManager(args=args, source_codes=_sources, llm=llm)
408
- target_files = index_manager.get_target_files_by_query(query)
409
-
410
- if target_files:
411
- final_files.extend(target_files.file_list)
412
-
413
- if target_files and args.index_filter_level >= 2:
414
-
415
- related_fiels = index_manager.get_related_files([file.file_path for file in target_files.file_list])
416
-
417
- if related_fiels is not None:
418
- final_files.extend(related_fiels.file_list)
419
-
420
- all_results = list({file.file_path: file for file in final_files}.values())
421
- printer.print_key_value(
422
- {"索引过滤级别": f"{args.index_filter_level}", "查询条件": f"{args.query}", "过滤后的文件数": f"{len(all_results)}"},
423
- panel=True
424
- )
425
-
426
- printer.print_table_compact(
427
- headers=["文件路径", "原因"],
428
- data=[[_target_file.file_path, _target_file.reason] for _target_file in all_results],
429
- title="Index Query 结果",
430
- show_lines=True,
431
- )
329
+ index_build_and_filter(llm=llm, args=args, sources_codes=project_source(source_llm=llm, args=args))
432
330
  return
433
331
 
434
332
 
@@ -481,42 +379,6 @@ def convert_config_value(key, value):
481
379
  return None
482
380
 
483
381
 
484
- # def update_config_to_args(query, delete_execute_file: bool = False):
485
- # conf = memory.get("conf", {})
486
- #
487
- # # 默认 chat 配置
488
- # yaml_config = {
489
- # "include_file": ["./base/base.yml"],
490
- # "skip_build_index": conf.get("skip_build_index", "true") == "true",
491
- # "skip_confirm": conf.get("skip_confirm", "true") == "true",
492
- # "chat_model": conf.get("chat_model", ""),
493
- # "code_model": conf.get("code_model", ""),
494
- # "auto_merge": conf.get("auto_merge", "editblock"),
495
- # "exclude_files": memory.get("exclude_files", [])
496
- # }
497
- # current_files = memory["current_files"]["files"]
498
- # yaml_config["urls"] = current_files
499
- # yaml_config["query"] = query
500
- #
501
- # # 如果 conf 中有设置, 则以 conf 配置为主
502
- # for key, value in conf.items():
503
- # converted_value = convert_config_value(key, value)
504
- # if converted_value is not None:
505
- # yaml_config[key] = converted_value
506
- #
507
- # yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
508
- # execute_file = os.path.join(args.source_dir, "actions", f"{uuid.uuid4()}.yml")
509
- #
510
- # with open(os.path.join(execute_file), "w") as f: # 保存此次查询的细节
511
- # f.write(yaml_content)
512
- #
513
- # convert_yaml_to_config(execute_file) # 更新到args
514
- #
515
- # if delete_execute_file:
516
- # if os.path.exists(execute_file):
517
- # os.remove(execute_file)
518
-
519
-
520
382
  def print_chat_history(history, max_entries=5):
521
383
  recent_history = history[-max_entries:]
522
384
  data_list = []
@@ -574,10 +436,8 @@ def chat(query: str, llm: AutoLLM):
574
436
  old_chat_history = json.load(f)
575
437
  if "conversation_history" not in old_chat_history:
576
438
  old_chat_history["conversation_history"] = []
577
- old_chat_history["conversation_history"].append(
578
- old_chat_history.get("ask_conversation", []))
579
- chat_history = {"ask_conversation": [
580
- ], "conversation_history": old_chat_history["conversation_history"]}
439
+ old_chat_history["conversation_history"].append(old_chat_history.get("ask_conversation", []))
440
+ chat_history = {"ask_conversation": [], "conversation_history": old_chat_history["conversation_history"]}
581
441
  else:
582
442
  chat_history = {"ask_conversation": [],
583
443
  "conversation_history": []}
@@ -604,8 +464,6 @@ def chat(query: str, llm: AutoLLM):
604
464
 
605
465
  if is_history:
606
466
  show_chat = []
607
- # if "conversation_history" in chat_history:
608
- # show_chat.extend(chat_history["conversation_history"])
609
467
  if "ask_conversation" in chat_history:
610
468
  show_chat.extend(chat_history["ask_conversation"])
611
469
  print_chat_history(show_chat)
@@ -618,13 +476,15 @@ def chat(query: str, llm: AutoLLM):
618
476
  chat_llm = llm
619
477
  pre_conversations = []
620
478
 
621
- if args.project_type == "py":
622
- pp = PyProject(llm=llm, args=args)
623
- else:
624
- pp = SuffixProject(llm=llm, args=args)
625
- pp.run()
626
- _sources = pp.sources
627
- s = build_index_and_filter_files(args=args, llm=llm, sources=_sources)
479
+ # if args.project_type == "py":
480
+ # pp = PyProject(llm=llm, args=args)
481
+ # else:
482
+ # pp = SuffixProject(llm=llm, args=args)
483
+ # pp.run()
484
+ # _sources = pp.sources
485
+ # _sources = project_source(source_llm=llm, args=args)
486
+ # s = build_index_and_filter_files(args=args, llm=llm, sources=_sources)
487
+ s = index_build_and_filter(llm=llm, args=args, sources_codes=project_source(source_llm=llm, args=args))
628
488
  if s:
629
489
  pre_conversations.append(
630
490
  {
@@ -639,50 +499,7 @@ def chat(query: str, llm: AutoLLM):
639
499
 
640
500
  loaded_conversations = pre_conversations + chat_history["ask_conversation"]
641
501
 
642
- v = chat_llm.stream_chat_ai(conversations=loaded_conversations, model=args.chat_model)
643
-
644
- MAX_HISTORY_LINES = 15 # 最大保留历史行数
645
- lines_buffer = []
646
- current_line = ""
647
- assistant_response = ""
648
-
649
- try:
650
- with Live(Panel("", title="Response", style="cyan"), refresh_per_second=12) as live:
651
- for chunk in v:
652
- if chunk.choices and chunk.choices[0].delta.content:
653
- content = chunk.choices[0].delta.content
654
- assistant_response += content
655
-
656
- # 处理换行符分割
657
- parts = (current_line + content).split('\n')
658
-
659
- # 最后一部分是未完成的新行
660
- if len(parts) > 1:
661
- # 将完整行加入缓冲区
662
- lines_buffer.extend(parts[:-1])
663
- # 保留最近N行历史
664
- if len(lines_buffer) > MAX_HISTORY_LINES:
665
- del lines_buffer[0: len(lines_buffer) - MAX_HISTORY_LINES]
666
- # 更新当前行(最后未完成的部分)
667
- current_line = parts[-1]
668
- # 构建显示内容 = 历史行 + 当前行
669
- display_content = '\n'.join(lines_buffer[-MAX_HISTORY_LINES:] + [current_line])
670
-
671
- live.update(
672
- Panel(Markdown(display_content), title="模型返回", border_style="cyan",
673
- height=min(25, live.console.height - 4))
674
- )
675
-
676
- # 处理最后未换行的内容
677
- if current_line:
678
- lines_buffer.append(current_line)
679
-
680
- # 最终完整渲染
681
- live.update(
682
- Panel(Markdown(assistant_response), title="模型返回", border_style="dim blue")
683
- )
684
- except Exception as e:
685
- printer.print_panel(Text(f"{str(e)}", style="red"), title="模型返回", center=True)
502
+ assistant_response = stream_chat_display(chat_llm=llm, args=args, conversations=loaded_conversations)
686
503
 
687
504
  chat_history["ask_conversation"].append({"role": "assistant", "content": assistant_response})
688
505
 
@@ -1841,20 +1658,10 @@ def main():
1841
1658
  memory["mode"] = "normal"
1842
1659
  event.app.invalidate()
1843
1660
 
1844
- # def _update_bottom_toolbar(toolbar_arg):
1845
- # if toolbar_arg in memory['conf']:
1846
- # return memory['conf'][toolbar_arg]
1847
- # return args.model_dump()[toolbar_arg]
1848
-
1849
1661
  def get_bottom_toolbar():
1850
1662
  if "mode" not in memory:
1851
1663
  memory["mode"] = "normal"
1852
1664
  mode = memory["mode"]
1853
- # skip_build_toolbar = _update_bottom_toolbar('skip_build_index')
1854
- # skip_filter_toolbar = _update_bottom_toolbar('skip_filter_index')
1855
- # index_filter_toolbar = _update_bottom_toolbar('index_filter_level')
1856
- # return (f" 当前模式: {MODES[mode]} (ctl+k 切换模式) | 跳过索引: {skip_build_toolbar} "
1857
- # f"| 跳过过滤: {skip_filter_toolbar} | 过滤等级: {index_filter_toolbar}")
1858
1665
  return f" 当前模式: {MODES[mode]} (ctl+k 切换模式) | 当前项目: {project_root}"
1859
1666
 
1860
1667
  session = PromptSession(
@@ -1924,10 +1731,10 @@ def main():
1924
1731
  index_query_command(query=query, llm=auto_llm)
1925
1732
  elif user_input.startswith("/index/export"):
1926
1733
  export_path = user_input[len("/index/export"):].strip()
1927
- index_export(export_path)
1734
+ index_export(project_root, export_path)
1928
1735
  elif user_input.startswith("/index/import"):
1929
1736
  import_path = user_input[len("/index/import"):].strip()
1930
- index_import(import_path)
1737
+ index_import(project_root, import_path)
1931
1738
  elif user_input.startswith("/list_files"):
1932
1739
  list_files()
1933
1740
  elif user_input.startswith("/conf"):
@@ -0,0 +1,64 @@
1
+ from rich.live import Live
2
+ from rich.panel import Panel
3
+ from rich.markdown import Markdown
4
+ from rich.text import Text
5
+
6
+ from autocoder_nano.llm_client import AutoLLM
7
+ from autocoder_nano.llm_types import AutoCoderArgs
8
+ from autocoder_nano.utils.printer_utils import Printer
9
+
10
+
11
+ printer = Printer
12
+
13
+
14
+ def stream_chat_display(
15
+ chat_llm: AutoLLM, args: AutoCoderArgs, conversations: list[dict], max_history_lines: int = 15, max_height: int = 25
16
+ ) -> str:
17
+ v = chat_llm.stream_chat_ai(conversations=conversations, model=args.chat_model)
18
+
19
+ lines_buffer = []
20
+ assistant_response = ""
21
+ current_line = ""
22
+
23
+ try:
24
+ with Live(Panel("", title="Response", style="cyan"), refresh_per_second=12) as live:
25
+ for chunk in v:
26
+ if chunk.choices and chunk.choices[0].delta.content:
27
+ content = chunk.choices[0].delta.content
28
+ assistant_response += content
29
+
30
+ # 处理换行符分割
31
+ parts = (current_line + content).split('\n')
32
+
33
+ # 最后一部分是未完成的新行
34
+ if len(parts) > 1:
35
+ # 将完整行加入缓冲区
36
+ lines_buffer.extend(parts[:-1])
37
+ # 保留最近N行历史
38
+ if len(lines_buffer) > max_history_lines:
39
+ del lines_buffer[0: len(lines_buffer) - max_history_lines]
40
+ # 更新当前行(最后未完成的部分)
41
+ current_line = parts[-1]
42
+ # 构建显示内容 = 历史行 + 当前行
43
+ display_content = '\n'.join(lines_buffer[-max_history_lines:] + [current_line])
44
+
45
+ live.update(
46
+ Panel(Markdown(display_content), title="模型返回", border_style="cyan",
47
+ height=min(max_height, live.console.height - 4))
48
+ )
49
+
50
+ # 处理最后未换行的内容
51
+ if current_line:
52
+ lines_buffer.append(current_line)
53
+
54
+ # 最终完整渲染
55
+ live.update(
56
+ Panel(Markdown(assistant_response), title="模型返回", border_style="dim blue")
57
+ )
58
+ except Exception as e:
59
+ printer.print_panel(Text(f"{str(e)}", style="red"), title="模型返回", center=True)
60
+
61
+ return assistant_response
62
+
63
+
64
+ __all__ = ["stream_chat_display"]
@@ -0,0 +1,93 @@
1
+ import json
2
+ import os
3
+ import shutil
4
+
5
+ from autocoder_nano.index.entry import build_index_and_filter_files
6
+ from autocoder_nano.index.index_manager import IndexManager
7
+ from autocoder_nano.index.symbols_utils import extract_symbols
8
+ from autocoder_nano.llm_client import AutoLLM
9
+ from autocoder_nano.llm_types import AutoCoderArgs, SourceCode
10
+ from autocoder_nano.project import project_source
11
+ from autocoder_nano.utils.printer_utils import Printer
12
+
13
+
14
+ printer = Printer()
15
+
16
+
17
+ def index_build(llm: AutoLLM, args: AutoCoderArgs, sources_codes: list[SourceCode] = None):
18
+ if not sources_codes:
19
+ sources_codes = project_source(source_llm=llm, args=args)
20
+ index = IndexManager(args=args, source_codes=sources_codes, llm=llm)
21
+ index.build_index()
22
+
23
+
24
+ def index_build_and_filter(llm: AutoLLM, args: AutoCoderArgs, sources_codes: list[SourceCode] = None) -> str:
25
+ if not sources_codes:
26
+ sources_codes = project_source(source_llm=llm, args=args)
27
+ return build_index_and_filter_files(args=args, llm=llm, sources=sources_codes)
28
+
29
+
30
+ def index_export(project_root: str, export_path: str) -> bool:
31
+ try:
32
+ index_path = os.path.join(project_root, ".auto-coder", "index.json")
33
+ if not os.path.exists(index_path):
34
+ printer.print_text(f"索引文件不存在. ", style="red")
35
+ return False
36
+
37
+ with open(index_path, "r", encoding="utf-8") as f:
38
+ index_data = json.load(f)
39
+
40
+ converted_data = {}
41
+ for abs_path, data in index_data.items():
42
+ try:
43
+ rel_path = os.path.relpath(abs_path, project_root)
44
+ data["module_name"] = rel_path
45
+ converted_data[rel_path] = data
46
+ except ValueError:
47
+ printer.print_text(f"索引转换路径失败. ", style="yellow")
48
+ converted_data[abs_path] = data
49
+
50
+ export_file = os.path.join(export_path, "index.json")
51
+ with open(export_file, "w", encoding="utf-8") as f:
52
+ json.dump(converted_data, f, indent=2)
53
+ printer.print_text(f"索引文件导出成功.", style="green")
54
+ return True
55
+ except Exception as err:
56
+ printer.print_text(f"索引文件导出失败: {err}", style="red")
57
+ return False
58
+
59
+
60
+ def index_import(project_root: str, import_path: str):
61
+ try:
62
+ import_file = os.path.join(import_path, "index.json")
63
+ if not os.path.exists(import_file):
64
+ printer.print_text(f"导入索引文件不存在. ", style="red")
65
+ return False
66
+ with open(import_file, "r", encoding="utf-8") as f:
67
+ index_data = json.load(f)
68
+ converted_data = {}
69
+ for rel_path, data in index_data.items():
70
+ try:
71
+ abs_path = os.path.join(project_root, rel_path)
72
+ data["module_name"] = abs_path
73
+ converted_data[abs_path] = data
74
+ except Exception as err:
75
+ printer.print_text(f"{rel_path} 索引转换路径失败: {err}", style="yellow")
76
+ converted_data[rel_path] = data
77
+ # Backup existing index
78
+ index_path = os.path.join(project_root, ".auto-coder", "index.json")
79
+ if os.path.exists(index_path):
80
+ printer.print_text(f"原索引文件不存在", style="yellow")
81
+ backup_path = index_path + ".bak"
82
+ shutil.copy2(index_path, backup_path)
83
+
84
+ # Write new index
85
+ with open(index_path, "w", encoding="utf-8") as f:
86
+ json.dump(converted_data, f, indent=2)
87
+ return True
88
+ except Exception as err:
89
+ printer.print_text(f"索引文件导入失败: {err}", style="red")
90
+ return False
91
+
92
+
93
+ __all__ = ["index_build", "index_export", "index_import", "index_build_and_filter", "extract_symbols", "IndexManager"]
@@ -1,5 +1,19 @@
1
+ from autocoder_nano.llm_client import AutoLLM
2
+ from autocoder_nano.llm_types import AutoCoderArgs, SourceCode
1
3
  from autocoder_nano.project.pyproject import PyProject
2
4
  from autocoder_nano.project.suffixproject import SuffixProject
3
5
  from autocoder_nano.project.tsproject import TSProject
4
6
 
5
- __all__ = ["PyProject", "SuffixProject", "TSProject"]
7
+
8
+ def project_source(source_llm: AutoLLM, args: AutoCoderArgs) -> list[SourceCode]:
9
+ if args.project_type == "py":
10
+ pp = PyProject(llm=source_llm, args=args)
11
+ elif args.project_type == "ts":
12
+ pp = TSProject(llm=source_llm, args=args)
13
+ else:
14
+ pp = SuffixProject(llm=source_llm, args=args)
15
+ pp.run()
16
+ return pp.sources
17
+
18
+
19
+ __all__ = ["PyProject", "SuffixProject", "TSProject", "project_source"]
@@ -0,0 +1,131 @@
1
+ import os
2
+ import uuid
3
+
4
+ import yaml
5
+ from jinja2 import Template
6
+
7
+ from autocoder_nano.llm_types import AutoCoderArgs
8
+ from autocoder_nano.utils.printer_utils import Printer
9
+
10
+
11
+ printer = Printer()
12
+
13
+
14
+ def convert_yaml_config_to_str(yaml_config):
15
+ yaml_content = yaml.safe_dump(
16
+ yaml_config,
17
+ allow_unicode=True,
18
+ default_flow_style=False,
19
+ default_style=None,
20
+ )
21
+ return yaml_content
22
+
23
+
24
+ def convert_config_value(key, value):
25
+ field_info = AutoCoderArgs.model_fields.get(key)
26
+ if field_info:
27
+ if value.lower() in ["true", "false"]:
28
+ return value.lower() == "true"
29
+ elif "int" in str(field_info.annotation):
30
+ return int(value)
31
+ elif "float" in str(field_info.annotation):
32
+ return float(value)
33
+ else:
34
+ return value
35
+ else:
36
+ printer.print_text(f"无效的配置项: {key}", style="red")
37
+ return None
38
+
39
+
40
+ def resolve_include_path(base_path, include_path):
41
+ if include_path.startswith(".") or include_path.startswith(".."):
42
+ full_base_path = os.path.abspath(base_path)
43
+ parent_dir = os.path.dirname(full_base_path)
44
+ return os.path.abspath(os.path.join(parent_dir, include_path))
45
+ else:
46
+ return include_path
47
+
48
+
49
+ def load_include_files(config, base_path, max_depth=10, current_depth=0):
50
+ if current_depth >= max_depth:
51
+ raise ValueError(
52
+ f"Exceeded maximum include depth of {max_depth},you may have a circular dependency in your include files."
53
+ )
54
+ if "include_file" in config:
55
+ include_files = config["include_file"]
56
+ if not isinstance(include_files, list):
57
+ include_files = [include_files]
58
+
59
+ for include_file in include_files:
60
+ abs_include_path = resolve_include_path(base_path, include_file)
61
+ # printer.print_text(f"正在加载 Include file: {abs_include_path}", style="green")
62
+ with open(abs_include_path, "r") as f:
63
+ include_config = yaml.safe_load(f)
64
+ if not include_config:
65
+ printer.print_text(f"Include file {abs_include_path} 为空,跳过处理.", style="green")
66
+ continue
67
+ config.update(
68
+ {
69
+ **load_include_files(include_config, abs_include_path, max_depth, current_depth + 1),
70
+ **config,
71
+ }
72
+ )
73
+ del config["include_file"]
74
+ return config
75
+
76
+
77
+ def convert_yaml_to_config(yaml_file: str | dict | AutoCoderArgs):
78
+ # global args
79
+ args = AutoCoderArgs()
80
+ config = {}
81
+ if isinstance(yaml_file, str):
82
+ args.file = yaml_file
83
+ with open(yaml_file, "r") as f:
84
+ config = yaml.safe_load(f)
85
+ config = load_include_files(config, yaml_file)
86
+ if isinstance(yaml_file, dict):
87
+ config = yaml_file
88
+ if isinstance(yaml_file, AutoCoderArgs):
89
+ config = yaml_file.model_dump()
90
+ for key, value in config.items():
91
+ if key != "file": # 排除 --file 参数本身
92
+ # key: ENV {{VARIABLE_NAME}}
93
+ if isinstance(value, str) and value.startswith("ENV"):
94
+ template = Template(value.removeprefix("ENV").strip())
95
+ value = template.render(os.environ)
96
+ setattr(args, key, value)
97
+ return args
98
+
99
+
100
+ def get_final_config(project_root: str, memory: dict, query: str, delete_execute_file: bool = False) -> AutoCoderArgs:
101
+ conf = memory.get("conf", {})
102
+ yaml_config = {
103
+ "include_file": ["./base/base.yml"],
104
+ "skip_build_index": conf.get("skip_build_index", "true") == "true",
105
+ "skip_confirm": conf.get("skip_confirm", "true") == "true",
106
+ "chat_model": conf.get("chat_model", ""),
107
+ "code_model": conf.get("code_model", ""),
108
+ "auto_merge": conf.get("auto_merge", "editblock"),
109
+ "exclude_files": memory.get("exclude_files", [])
110
+ }
111
+ current_files = memory["current_files"]["files"]
112
+ yaml_config["urls"] = current_files
113
+ yaml_config["query"] = query
114
+
115
+ # 如果 conf 中有设置, 则以 conf 配置为主
116
+ for key, value in conf.items():
117
+ converted_value = convert_config_value(key, value)
118
+ if converted_value is not None:
119
+ yaml_config[key] = converted_value
120
+
121
+ execute_file = os.path.join(project_root, "actions", f"{uuid.uuid4()}.yml")
122
+ try:
123
+ yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
124
+ with open(os.path.join(execute_file), "w") as f: # 保存此次查询的细节
125
+ f.write(yaml_content)
126
+ args = convert_yaml_to_config(execute_file) # 更新到args
127
+ finally:
128
+ if delete_execute_file:
129
+ if os.path.exists(execute_file):
130
+ os.remove(execute_file)
131
+ return args
autocoder_nano/version.py CHANGED
@@ -1,3 +1,3 @@
1
- __version__ = "0.1.35"
1
+ __version__ = "0.1.37"
2
2
  __author__ = "moofs"
3
3
  __license__ = "Apache License 2.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: autocoder_nano
3
- Version: 0.1.35
3
+ Version: 0.1.37
4
4
  Summary: AutoCoder Nano
5
5
  Author: moofs
6
6
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
@@ -1,5 +1,5 @@
1
1
  autocoder_nano/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- autocoder_nano/auto_coder_nano.py,sha256=-_GJVdBRQs1SXmfxzhIqMMRTZZNjvpUo8y5Z4UjD_1Y,82353
2
+ autocoder_nano/auto_coder_nano.py,sha256=AMJiNqQyEKaU5KqEOo9EzQwQDi5K3lr4YTeuMqdqWSA,74671
3
3
  autocoder_nano/auto_coder_nano_rag.py,sha256=9BtNZ6nC5D5SPTIuziXZOfouCBLOMNzvJMTdDPQEgO8,10436
4
4
  autocoder_nano/auto_coder_nano_ui.py,sha256=ZBskcIJMeTJY7_JipGJaee58G9fUJaOv3LV4hptLc6c,12669
5
5
  autocoder_nano/file_utils.py,sha256=iGbkbQ191nKL4aNufdexYYYQSDM1XrDC9Uxp_PIbawY,661
@@ -10,7 +10,7 @@ autocoder_nano/llm_prompt.py,sha256=ViWUfCZp0gDESAAPHBhZc2WhHiFUHIxK6a2xbFu0sjU,
10
10
  autocoder_nano/llm_types.py,sha256=T0ugeWdwejy6BJaQrAlk8Pk5qweW2xbggxzHaSpTBOg,11588
11
11
  autocoder_nano/sys_utils.py,sha256=Sn6kr5diaEkVWbYDBrtenr9zw32jVIWvsAReY7_uEd0,1638
12
12
  autocoder_nano/templates.py,sha256=fqlRtnx6HvPE4CbdnPcnLBB-flPwufwcGRpsFD3aW2c,4271
13
- autocoder_nano/version.py,sha256=EHHVoJOXjCkEUL-Zl_GcPBCR9AFZZUcSa1h_MximxjQ,79
13
+ autocoder_nano/version.py,sha256=zGimidx6OporaPNCY3Rm74IgiKpb8FGFXs-gXvOb2SY,79
14
14
  autocoder_nano/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  autocoder_nano/agent/agent_base.py,sha256=O5Hq6VnoqrXnBE_oXZHXlbmSRdOEe28H65bJ1WhAQjg,16377
16
16
  autocoder_nano/agent/agentic_edit.py,sha256=I1HjRhMabDmtfxcCOKawUJV0wU1GNzKtof19_GNgAjU,88749
@@ -48,6 +48,7 @@ autocoder_nano/app/templates/partials/examples.html,sha256=_i7TfpcRqW-IvI69vVXYe
48
48
  autocoder_nano/app/templates/partials/header.html,sha256=txCMUmFFWSEDz5xxQwt8oBko8Y_b1bSsVASVOMCsILo,300
49
49
  autocoder_nano/app/templates/partials/input.html,sha256=8CY3JcHaA4nPZ2Vu4ragdYZzzodvF0isQiOGHtdQs6k,1956
50
50
  autocoder_nano/app/templates/partials/message.html,sha256=HWEh_j_yJAbP7zFs6jt88BDzkP7dG6VgPUbS2MT5Ax4,1548
51
+ autocoder_nano/chat/__init__.py,sha256=FuXp0tcnegngct9Jp8HbgwFkwnhxMirwNFHtoa_vACw,2441
51
52
  autocoder_nano/data/tokenizer.json,sha256=7Lb5_DaYlDRvBRH0B0ynXO5c1fOwbQLxujX805-OEh0,7847602
52
53
  autocoder_nano/edit/__init__.py,sha256=QPMuW7tBTUe0Q00gUPJEmdxWqvunqko9_dsim0ncr7c,623
53
54
  autocoder_nano/edit/actions.py,sha256=N4qzSIE7Ifm7r6Sk-HbgWmbDqMP6jfrpByfpV7rbEo8,6480
@@ -56,11 +57,11 @@ autocoder_nano/edit/code/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
56
57
  autocoder_nano/edit/code/generate_editblock.py,sha256=s-VTZK0G1OhjEyZXqyjj4sY48fOo02EvHhaxTIw4ytY,13110
57
58
  autocoder_nano/edit/code/merge_editblock.py,sha256=Vk-FOVvaEzKcSRDMyMyR_M77kqj-s5-zejChn4QwLAY,17557
58
59
  autocoder_nano/edit/code/modification_ranker.py,sha256=hnF1acqAzPYKm9hEFxobJHfGGDdM-GclZLxvtt83lGA,3431
59
- autocoder_nano/index/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
+ autocoder_nano/index/__init__.py,sha256=fYrXsjRMrL2cjHjH37Bcl51Uqr17_aqlTH-c_2WQcok,3767
60
61
  autocoder_nano/index/entry.py,sha256=S71dfnYC201eQLXwqNCo_Y83ImI1ZxuJ0_m2hz5nCJc,7729
61
62
  autocoder_nano/index/index_manager.py,sha256=ek7AqU8M-Snl5qZYhO_U0SEK3-y1u5OOxD9z-LdDesE,15619
62
63
  autocoder_nano/index/symbols_utils.py,sha256=z_16X6BozTfmric1uU-r2GqzDabJ5ChfAOB4lo7i-_8,1450
63
- autocoder_nano/project/__init__.py,sha256=8R90zhCcRTHWScAOYw20lkcHI4IhSm-ywCLcfezn0Oc,227
64
+ autocoder_nano/project/__init__.py,sha256=KfSsvUVi-MCUJ-AITl8jQpOTPMIW55VmwPzSUP6LnlI,708
64
65
  autocoder_nano/project/pyproject.py,sha256=UZqHBrUmsCW73YkG8shjeFSEYGB_zFDH1ezoPP_f33Q,4478
65
66
  autocoder_nano/project/suffixproject.py,sha256=190GCS25qYi4kPav0Hpk2qgSFalkvJk7VM_pchnfurY,4717
66
67
  autocoder_nano/project/tsproject.py,sha256=3gBS-2aup2W5ehSbhD7Bdr-9v9uL7MgY_7TkLHShh9I,5565
@@ -86,12 +87,13 @@ autocoder_nano/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
86
87
  autocoder_nano/tools/http_tools.py,sha256=04Tmg8BTwfsw7_-fKBDHv787XU4yQ5UtQSDj0zJBIUc,3189
87
88
  autocoder_nano/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
88
89
  autocoder_nano/utils/completer_utils.py,sha256=MGA3r5pAvDhp1vNGGCyjHWDtqXnd-CF4zPw7uawSzNM,25556
90
+ autocoder_nano/utils/config_utils.py,sha256=r5n0De4mz5sL_nj-CeT_F5TxtgWQIN5vv0Z5FiP8GXA,4800
89
91
  autocoder_nano/utils/formatted_log_utils.py,sha256=1d3xvZ1Bo3-I1wQOMdXpwsMX5cl2FWkmpgHGHvTPEvI,5457
90
92
  autocoder_nano/utils/printer_utils.py,sha256=6rGHihCh8DDESWs6qWqwsf3B6qaeM_CNx6crzkl9UCk,15303
91
93
  autocoder_nano/utils/shell_utils.py,sha256=llVTrOrmS1RH2ws7W69tofVtf53Kq04uh-sURphejrU,2477
92
- autocoder_nano-0.1.35.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
93
- autocoder_nano-0.1.35.dist-info/METADATA,sha256=e5LU59CY6BwcJrQKIxMt2BdsQlnu_vHra50sL4EKsDc,13591
94
- autocoder_nano-0.1.35.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
95
- autocoder_nano-0.1.35.dist-info/entry_points.txt,sha256=Dj8gGZ_AgLy8ANqr2do_DJjpsR3JMh-ztsrUXo4Vn5Q,194
96
- autocoder_nano-0.1.35.dist-info/top_level.txt,sha256=D7s34cwIs1F4EAjRRDvO_zTHtUz1Z7UVccFUNlJn7HI,15
97
- autocoder_nano-0.1.35.dist-info/RECORD,,
94
+ autocoder_nano-0.1.37.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
95
+ autocoder_nano-0.1.37.dist-info/METADATA,sha256=hHgyCckA57oWf1OHZlguJgB9IMxqiolJp-6jyQ3yxvY,13591
96
+ autocoder_nano-0.1.37.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
97
+ autocoder_nano-0.1.37.dist-info/entry_points.txt,sha256=Dj8gGZ_AgLy8ANqr2do_DJjpsR3JMh-ztsrUXo4Vn5Q,194
98
+ autocoder_nano-0.1.37.dist-info/top_level.txt,sha256=D7s34cwIs1F4EAjRRDvO_zTHtUz1Z7UVccFUNlJn7HI,15
99
+ autocoder_nano-0.1.37.dist-info/RECORD,,